scanning a float, getting seemingly random values - math

I was given an assignment to create a procedure that scans a float, called getfloat.
for some reason, I am getting random values. If I enter "1" it prints 49.Why does this happen? And also, when i input values, I can't see them on the screen? when I use scanf for example i see what i hit, on the little black screen. but now the screen is just blank, and when i click enter it shows a bad output:
Example - input: -1. Output: 499.00000
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>
void getfloat(float* num);
void main()
{
float num=0;
printf("Enter the float\n");
getfloat(&num);
printf("\nThe number is %lf\n",num);
getch();
}
void getfloat(float* num)
{
float c,sign=1,exponent=10;
c=getch();
if((!isdigit(c))&&(c!='+')&&(c!='-')) //if it doesnt start with a number a + or a -, its not a valid input
{
printf("Not a number\n");
return;
}
if(c=='-') //if it starts with a minus, make sign negative one, later multiply our number by sign
sign=-1;
for(*num=0;isdigit(c);c=getch())
*num=(*num*10)+c; //scan the whole part of the number
if(c!='.') //if after scanning whole part, c isnt a dot, we finished
return;
do //if it is a dot, scan fraction part
{
c=getch();
if(isdigit(c))
{
*num+=c/exponent;
exponent*=10;
}
}while(isdigit(c));
*num*=sign;
}

There are a number of issues.
1) Your posted code does not match your example "input: -1. Output: 499.00000", I get 0 due the lack of a getch() after finding a '-'. See #6.
1) 'c' is a character. When you enter '1', c took on a code for the letter 1, which in your case being ASCII coding, is 49. To convert a digit from its ASCII value to a number value, subtract 48 (the ASCII code for the letter '0', often done as c - '0'
*num=(*num*10)+c;
*num+=c/exponent;
becomes
*num = (*num*10) + (c-'0');
*num += (c-'0')/exponent;
2) Although you declare c as a float, recommend you declare it as an int. int is the return type from getch().
3) Function getch() is "used to get a character from console but does not echo to the screen". That is why you do not see them. Consider getchar() instead.
4) [Edit: delete Avoid =-. Thank-you #Daniel Fischer]
5) Your exponential calculation needs rework. Note: your exponent could receive a sign character.
6) When you test if(c=='-'), you do not then fetch another c. You also might want to test for else if(c=='+') and consume that c.
Good luck in your C journey.

49 is the Ascii code for the number 1. So when (0'<=c && c <='9') you need to subtract '0' to get the number itself.

A small hint: 49 is the ASCII for the character 1. You are using getch(), which gives you the return value char.

Related

displaying double variable problem (Arduino)

so I have a problem with displaying a double variable in OLED & IR remote calculator, like this (using u8g2):
displayTextOnRight(String(100000, 0)); //ex. of an void and a number
It displays: " "
But when I set to ex. 99999 it displays: "99999"
The same is with
displayTextOnRight(String(1000.00, 2));
It also displays nothing. (100.00 displays 100.00)
I tried values below zero and it crashes. When I try 6 it's empty whatever I type on my remote.
Please help.
You're wrong. This would not work neither as you obviously expect
void setup() {
Serial.begin(9600);
Serial.print("Test: ");Serial.println(String(99999,0));
}
The function String handles integers differently than floats:
for floats you specify the number of decimal digits ( 2 as default )
for int you specify the radix ( DEC as default )

Arduino sketch with Serial.available() passes twice

When I test Serial.available() or Serial.available() > 0 in my loop() function, it appears to return true twice each time I enter serial data. The second time, it sets the throttle value in my code to 0. Here is the code:
#include <Servo.h>
Servo rc_rotor;
int throttle = 0; // servo position indicates throttle position.
String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";
void setup()
{
rc_rotor.attach(9);
Serial.begin(9600);
while(! Serial);
Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}
void loop()
{
rc_rotor.write(throttle);
delay(20);
if (Serial.available())
{
int temp_throttle = Serial.parseInt();
if (temp_throttle >= 0 && temp_throttle <= 180)
{
throttle = temp_throttle;
Serial.println(s_throttle_set + throttle);
}
else if (temp_throttle == 999)
{
Serial.println(s_throttle_read + throttle);
}
else
{
Serial.println(s_action_error + temp_throttle);
}
}
}
Please note this code is not my final masterpiece. Much of it is from publicly available examples. Anyway, the statement if (Serial.available()) succeeds twice. By that I mean, it is true when I type in a value such as 125, and a moment later it will be 'true' again when I have typed in nothing additional. I only expect one value to go through this way. The result is that my throttle is being set to the value I enter, and then almost immediately re-set to 0. Why would something like this happen?
It turns out there is no mysterious problem with the hardware or the code, as I first suspected there was. Actually, the solution is simply to select "no line ending" in the Arduino Serial Monitor's dropdown option (by default, I guess mine was set to "New Line"). Without the additional character being inserted by the Serial Monitor, everything behaves as expected.
One thing I did not expect is how the Arduino software interprets the newline. I debugged by printing the ascii values that were making it through my if-statement. First of all, the Serial Monitor sent the number I typed in, followed moments later by ascii 10, which is the line feed character. Fine, no problem. But then Serial.parseInt() chewed on that line feed for a moment (there was a slight but noticeable delay), then fed the numeral 0 to my function. It took me a little while to figure out why. Here is an explanation from the Serial part of the Arduino Language Reference:
parseInt()
Description
Looks for the next valid integer in the incoming serial stream.
parseInt() inherits from the Stream utility class.
In particular:
Initial characters that are not digits or a minus sign, are skipped;
Parsing stops when no characters have been read for a configurable
time-out value, or a non-digit is read;
If no valid digits were read
when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
So Serial.available() is true after the line feed character enters the buffer, but there is no "valid digit" according to Serial.parseInt(). Understandably... we are looking at an empty buffer that finally times out. Therefore Serial.parseInt() returns 0 and the code that follows proceeds with that value.
The code in the question assumed that the only input would be integers coming over the serial connection, which is actually a pretty fragile assumption. If you need to use Serial.parseInt in a situation where empty buffers (null), line feeds or other unexpected characters might come through, it should just be a matter of filtering the input better than I did in the example code.

Microcontroller, How to display decimal on LCD?

I have a microcontroller and I am sampling the values of an LM335 temperature sensor.
The LCD library that I have allows me to display the hexadecimal value sampled by the 10-bit ADC.
10bit ADC gives me values from 0x0000 to 0x03FF.
What I am having trouble is trying to convert the hexadecimal value to a format that can be understood by regular humans.
Any leads would be greatly appreciated, since I am completely lost on the issue.
You could create a "string" into which you construct the decimal number like this (constants depend on what size the value actually, I presume 0-255, whether You want it to be null-terminated, etc.):
char result[4];
char i = 3;
do {
result[i] = '0' + value % 10;
value /= 10;
i--;
}
while (value > 0);
Basically, your problem is how to split a number into decimal digits so you can use your LCD library and send one digit to each cell.
If your LCD is based on 7-segment cells, then you need to output a value from 0 to 9 for each digit, not an ASCII code. The solution by #Roman Hocke is fine for this, provided that you don't add '0' to value % 10
Another way to split a number into digits is to convert it into BCD. For that, there is an algorithm named "double dabble" which allows you to convert your number into BCD without using divisions nor module operations, which can be nice if your microcontroller has no provision for division operation, or this is slower than you need.
"Double dable" algorithm sounds perfect for microcontrollers without provision for the division operation. However, a quick oversight of such algorithm in the Wikipedia shows that it uses dynamic memory, which seems to be worst than a routine for division. Of course, there must be an implementation out there that are not using calls to malloc() and friends.
Just to point out that Roman Hocke's snippet code has a little mistake. This version works ok for decimals in the range 0-255. It can be easily expand it to any range:
void dec2str(uint8_t val, char * res)
{
uint8_t i = 2;
do {
res[i] = '0' + val % 10;
val /= 10;
i--;
} while (val > 0);
res[3] = 0;
}

Format string from scientific notation into decimal one

I have a string like that "2.1648797E -05" and I need to format it to convert "0.00021648797"
Is there any solution to do this conversion
try to use double or long long
cout << setiosflags(ios::fixed) << thefloat << endl;
An important characteristic of floating point is that they do not have precision associated with all the significant figures back to the decimal point for large values. The "scientific" display reasonably reflects the inherent internal storage realities.
In C++ you can use std::stringstream First print the number, then read it as double and then print it using format specifiers to set the accuracy of the number to 12 digits. Take a look at this question for how to print decimal number with fixed precision.
If you are really just going from string representation to string representation and precision is very important or values may leave the valid range for doubles then I would avoid converting to a double.
Your value may get altered by that due to precision errors or range problems.
Try writing a simple text parser. Roughly like that:
Read the digits, omitting the decimal point up to the 'E' but store the decimal point position.
After the 'E' read the exponent as a number and add that to your stored decimal position.
Then output the digits again properly appending zeros at beginning or end and inserting the decimal point.
There are unclear issues here
1. Was the space in "2.1648797E -05" intended, let's assume it is OK.
2. 2.1648797E-05 is 10 times smaller than 0.00021648797. Assume OP meant "0.000021648797" (another zero).
3. Windows is not tagged, but OP posted a Windows answer.
The major challenge here, and I think is the OP's core question is that std::precision() has different meanings in fixed versus default and the OP wants the default meaning in fixed.
Precision field differs between fixed and default floating-point notation. On default, the precision field specifies the maximum number of useful digits to display both before and after the decimal point, possible using scientific notation, while in fixed, the precision field specifies exactly how many digits to display after the decimal point.
2 approaches to solve this: Change the input string to a number and then output the number in the new fixed space format - that is presented below. 2nd method is to parse the input string and form the new format - not done here.
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cmath>
#include <cfloat>
double ConvertStringWithSpaceToDouble(std::string s) {
// Get rid of pesky space in "2.1648797E -05"
s.erase (std::remove (s.begin(), s.end(), ' '), s.end());
std::istringstream i(s);
double x;
if (!(i >> x)) {
x = 0; // handle error;
}
std::cout << x << std::endl;
return x;
}
std::string ConvertDoubleToString(double x) {
std::ostringstream s;
double fraction = fabs(modf(x, &x));
s.precision(0);
s.setf(std::ios::fixed);
// stream whole number part
s << x << '.';
// Threshold becomes non-zero once a non-zero digit found.
// Its level increases with each additional digit streamed to prevent excess trailing zeros.
double threshold = 0.0;
while (fraction > threshold) {
double digit;
fraction = modf(fraction*10, &digit);
s << digit;
if (threshold) {
threshold *= 10.0;
}
else if (digit > 0) {
// Use DBL_DIG to define number of interesting digits
threshold = pow(10, -DBL_DIG);
}
}
return s.str();
}
int main(int argc, char* argv[]){
std::string s("2.1648797E -05");
double x = ConvertStringWithSpaceToDouble(s);
s = ConvertDoubleToString(x);
std::cout << s << std::endl;
return 0;
}
thanks guys and i fix it using :
Decimal dec = Decimal.Parse(str, System.Globalization.NumberStyles.Any);

Arduino serial data parsing

I'm writing an app to control my robot with my Android phone over Bluetooth, everything is goes well, data is echoed and verified, but I'm having some trouble with the protocol, specifically I want my robot's wheels to turn when I send a command such as s,10,100 or s,-30,-10... (values in percent).
My problem is that when I want to parse my wheel speed command on my Arduino I must parse from up to 4 separate bytes to int, for example s,-100,-100 makes my robot go backwards at full speed, but how do I parse this so I can call setSpeed(left, right); with leftand right equal to -100?
I know I can separately analyse every byte and put them together to get an integer, but it's not very elegant and there's probably a better solution to all this already, unfortunately I haven't found it yet.
EDIT
Here's my Arduino function for parsing my commands:
void parseCommand(char* command, int* returnValues)
{
// parsing state machine
byte i = 2, j = 0, sign = 0;
int temp = 0;
while(*(command + i) != '\0')
{
switch(*(command + i))
{
case ',':
returnValues[j++] = sign?-temp:temp;
sign = 0;
temp = 0;
break;
case '-':
sign = 1;
break;
default:
temp = temp * 10 + *(command + i) - 48;
}
i++;
}
// set last return value
returnValues[j] = sign?-temp:temp;
}
You call it this way when parsing something like s,100,-100 (must be \0 terminated):
char serialData[16];
void loop()
{
if(Serial.available() > 0)
{
Serial.readBytesUntil('\0', serialData, 15);
switch(serialData[0])
{
case 's':
int speed[2];
parseCommand(serialData, speed);
setSpeed(speed[0], speed[1]);
break;
}
// always echo
Serial.write(serialData);
// end of message is maked with a \0
Serial.print('\0');
// clear serialData array
memset(serialData, 0, sizeof(serialData));
}
}
Just read character by character into a state machine. It's simple and efficient.
To read in a number digit by digit, do this: Start with zero. For each digit, multiply the number by ten and add the value of the digit. So, for example, reading 97 would work like this:
You read in a digit with no prior digit, you start with 0.
You read in 9 and compute (0*10)+9 -> 9
You read in 7 and compute (9*10)+7 -> 97
You read in a non-digit, you output the 97.
Here's a fuller example s,10,100:
You start in the "ready to read command state".
You read "s", "s" is the command. You switch to the "ready to read first comma" state.
You read the first comma, you switch to the "ready to figure out the sign of the first parameter" state.
You read a digit. Since this wasn't a "-", the first parameter is positive. You set the first number to the value of the digit, 1. You are now in "reading first number" state.
You read a digit, 0. You set the first number to 1*10+0 -> 10. You are still in "reading first number" state.
You read a comma. You are now in the "ready to figure out sign of the second parameter" state.
You read 1. The second number is positive (since this wasn't a "-"). You set the second number to 1. You are in the "reading second number" state.
You read 0. The second number is now set to 1x10+0 -> 10. You are still in "reading second number" state.
You read 0. The second number is now set to 10x10+0 -> 100. You are still in "reading second number" state.
You read an end of line. You execute your results: The command is "s", the first number is positive, the first number is 10, the second number is positive, the second number is 100.
You switch back to "ready to read command" state.
I like the answer by David Swartz, but thought I'd play devil's advocate.
Reading the data in as binary can be elegant, it just depends on what you need to do with it.
In the following example, data is read from serial until it sees the binary delimiter 0X7F. The bytes read are stored in the inData char array. Take a look at the documentation for Serial.readBytesUntil()
char inData[16];
int bRead;
bRead = Serial.readBytesUntil(0x7F,inData,4);
This byte can then be cast to an integer or otherwise manipulated. Keep in mind the maximum value for this would be +/-126 because this is a signed char (127 is a delimiter and wouldn't be seen as a value).
You could access these values by with something like the following:
Serial.print("Bytes Read: ");
Serial.println(bRead);
Serial.println("First Byte");
Serial.println((int)inData[0]);
Serial.println(
map((int)inData[0],0,126,0,1024)
);
Serial.println("Second Byte");
Serial.println((int)inData[1]);
I tested this out with the following bash command (after making sure serial speeds were set properly):
echo -ne '\x01\x02\x7F' > /dev/ttyACM0
Some rough sample code that I wrote can be found Here

Resources