[AVOIDED ERROR/SOLVED] Loss on float Number Precision

Hi all,

I am doing a simple conversion from a serial read string to a float number, mapping the number to a servo position and confirming servo positioning. Currently I run into a problem and which I can't figure why is happening! I was confirming float conversion by printing it back to serial monitor. Here was when things did not went well, some numbers loss precision...

Here goes an example and a piece of code with this problem:

Typed & Expected - Printing Result

"51.00000!" - "51.000000" "51.00100!" - "51.000999" "51.00200!" - "51.001998"

int overChar; 
String CommandString;
float S1Position;

void setup() {
     Serial.begin(115200);
}

void loop() {
          if (Serial.available() > 0) {
           CommandString = "";
           overChar = 0;
            while(overChar != '!' ){        // term. Char
              if (Serial.available() > 0) {
                overChar = Serial.read();
                CommandString += (char)overChar;
              }
            }
              S1Position = constrain(CommandString.toFloat(), 0, 100);
              Serial.println(S1Position,6);
          }
        }

As in example, the code has a termination char, so when finish typing the serial string end with "!" or it will be reading for ever...

Can anyone tell me why this happens?

A long time ago got some Matlab issue like this. It was related with non definition of the number of precision digits to transport in operations (more like error propagation), but was far more complicated than a simple feed back like this.

Looks about right to me, that is about all you can expect with a float.

If you are mapping the float to a servo position then loss of .00002 is not going to make much difference is it ?

If you want precision, ditch the floats which are inherently imprecise by their very nature and use integers which are always precise to a given number of places. For instance unsigned long will give you 9 digits of precision that you can count on.

Hello,

DMartin5:
…mapping the number to a servo position and confirming servo positioning…

Typed & Expected - Printing Result

“51.00000!” - “51.000000”
“51.00100!” - “51.000999”
“51.00200!” - “51.001998”

(51.00100-51.000999)/51.001001000000000 = 19.6
(51.00200-51.001998)/51.00200
1000000000 = 39.2

You have a servo that is accurate to 40ppb? How much did that set you back?

I hope it is a misguided coding scheme. The '51' is a particular servo and the '001' is the servo position. If that is the case, then the obvious answer is to parse the string and forget about all the float nonsense.

KeithRB: I hope it is a misguided coding scheme. The '51' is a particular servo and the '001' is the servo position. If that is the case, then the obvious answer is to parse the string and forget about all the float nonsense.

there is only one println in the OP's code, so the 51 is part of the position

              S1Position = constrain(CommandString.toFloat(), 0, 100);
              Serial.println(S1Position,6);

DMartin5: Can anyone tell me why this happens?

The internal accuracy of "float" is 6-7 significant digits, depending on the actual function you are using.

If you just assign a float and print the value, its accuracy is "7 significant digits".

So to stay accurate with a float value with 2 digits before the decimal point, you can have 5 digits after the decimal point.

So this is what you can use in your code to stay accurate:

Serial.println(S1Position,5);

You cannot calculate more significant digits from a "float" number than max 7 (or 6) significant digits, which is the internal accuracy.

My rule is: always treat a floating point value as an approximation of some real value. Floats are ok for things like physical measurements, statistical averages, and trigonometry. They are not ok for anything that needs to be measured precisely in units, such as date/time or currency.

Thak you all for your opinions!

[quote author=Coding Badly link=msg=2237566 date=1431976939]

You have a servo that is accurate to 40ppb? How much did that set you back?

[/quote]

I understand most of your concerns about the precision of this "servo". Actually you are right! Is not a servo that I am controlling is more like a "complex multi encoder positioner" and the example is not quite like this (at all...). I am just using Arduino for the sake of simplicity prototyping... I do have a more complex controller to implement.

Despite all that, the concern is that the significant digits are like a "trim correction value" and carry more information than the position. I was just trying to use float to decrease the amount of protocol needed. This doubt just intrigued me and I was curious. I found jurs post the most explanatory. After reading, I have modified the code for an Int type number with minimum digits required. Then, just multiplied for 0.000001 to get the precision needed.

Again, thank you all for the kind support!