I am currently working on a project where i take a frequency, and i want the code to take that value and use a formula to work out its mmh2O level. I use the Serial Monitor to input the values, but i have a problem. When writing the values e.g. "44.62352548","44.49151522". The value that is sent is wrong and displayed wrong. enter image description here
I know the code i have written does not support this many signigicant figures from a float. And i have tried a few things to try and solve it but i cannot crack it.
I have tried using dtostrf() command, but i have never used this before and dont understand. Somebody from the arduino Forums had helped me out but it didnt seem to work. I have also tried formatting aswell, and that did not seem to work.
If anyone has any help and advice it would be much appreciated.
float level;
float myValue;
String msg1 = "Enter Frequency (type 0 to exit): ";
String msg2 = "Your Frequency is: ";
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.print(msg1);
while (Serial.available() == 0);
{
}
myValue = Serial.parseFloat();
if (myValue == 0.0)
{
Serial.end();
}
else
{
freqConversion();
}
}
void freqConversion()
{
level = (myValue-44.712)/-0.0285493333;
Serial.println(myValue);
Serial.print(msg2);
Serial.println(level);
}
-
What do you mean by "The value that is sent is wrong and displayed wrong"? What did you expect? What was displayed instead?Edgar Bonet– Edgar Bonet2020年12月04日 13:32:27 +00:00Commented Dec 4, 2020 at 13:32
-
added image of the resultJack Lythgoe– Jack Lythgoe2020年12月04日 13:36:19 +00:00Commented Dec 4, 2020 at 13:36
-
no images please ... add the text and format as codejsotola– jsotola2020年12月04日 15:10:56 +00:00Commented Dec 4, 2020 at 15:10
1 Answer 1
You have hit a bug in the implementation of parseFloat()
.
This function reads the number you send as an integer, ignoring
the decimal point, and stores it in a long
. It then multiplies it by a
scaling factor (a power of 0.1) in order to get the correct value. The
problem is, if you provide too many significant digits, the integer
overflows, and you get garbage. For example "44.64978683" is interpreted
as
(long) 4464978683 * 0.00000001
but (long) 4464978683
overflows and rolls over to 170011387, hence the
result you get.
Simple workaround: do not provide so many significant digits. They are
irrelevant anyway given the resolution of a float
.
Edit: I did not find any bug report for this issue, so I submitted my own to the Arduino dev team.
Update: Per request of a maintainer, I submitted a pull request with a failing unit test revealing this bug. We then worked on a fix, which has now been merged to master. It should be published on the next release of ArduinoCore-API.
Note, however, that the AVR core does not yet use the common API repository. In the meantime, it may be worth submitting a pull request to ArduinoCore-avr that cherry-picks the fix from ArduinoCore-API.