3

I'm trying to convert a String to a float but I'm running into issues with precision, even with the Arduino's own String example I'm getting bad results.

Example 0: Input string: 1.234567 After conversion to float: 1.2345669

Example 1: Input string: 60.123456 After conversion to float: 60.1234512

Example 2: Input string: 9.876543 After conversion to float:9.8765430

Why is this happening and how do I get rid of this?

4 Answers 4

2

You get this, because a float uses a certain number of bytes (I don't have an Arduino at hand), I think it is 4 bytes.

In these bytes, only a certain accuracy can be stored, so the least significant digits gets rounded (binary, resulting in different end digits).

Only for e.g. Arduino Due: You can use doubles instead, see https://www.arduino.cc/reference/en/language/variables/data-types/double/

You might check for the strtod function, but I'm not sure if it is handled by the Arduino:

https://www.techonthenet.com/c_language/standard_library_functions/stdlib_h/strtod.php

If this doesn't work, you can use a function to split the '.' and process the left/right part to convert to an unsigned long and combine it together. But if there are exponential and minus signs involved it might get more difficult.

2
  • 1
    A float is 32 bits. On AVR boards, double is just a synonym of float. Commented Jan 6, 2020 at 17:52
  • @EdgarBonet Thanks for that remark, I updated my answer (Only for Arduino Due). Commented Jan 6, 2020 at 20:08
1

There are two issues at play here:

1 – Limited precision of the float data type

A float has a precision of roughly 10−7, and any number that is not an exact float is supposed to be rounded to the nearest float. For example, the two floats closest to 1.234567 are
10356298 × 2−23 = 1.2345669269561767578125 and
10356299 × 2−23 = 1.23456704616546630859375.
The latter is the closest.

2 – Naive string to float implementation in the Arduino core

The Arduino core aims at being small and consume few resources. Sometimes it cuts corners, at the cost of accuracy. In this case, although a correct implementation is supposed to round 1.234567 up, because the nearest float is above that number, the actual implementation ends up rounding down. Thus you end up with roughly 1.234566927, which is off by 0.61 ULPs (units of the last place), instead of the expected error of 0.39 ULPs.

0

It seems that I must convert to string first then use atof.

0

If you are using atof() to convert the string to a floating-point number, you would only get 6 or 7 digits of precision. And the numbers in your examples already have that much precision.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.