This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/TMS320F28388D: conversions between strings and floats

Part Number: TMS320F28388D

Tool/software: TI C/C++ Compiler

We are seeing some unexpected behavior when using strtof and snprintf with the %f format when converting between strings and floats. We are using the ti-cgt-c2000_20.2.2.TLS library for the ARM on the CM. 

strtof:

if you enter the string 15.000 it converts just fine but if you enter 15.000000000000000 you get 15.000005. When single stepping through the routine on line 170 result*base gets large and adding 0 to the value actually adds a non-zero amount. N + 0 does not equal N any longer? I think it was around when base was 1e9 or 1e10. 15.0000000000000000 only has two significant digits and is easily represented in floating point without error but the strtof does not convert without adding error for large number of zeros. 

As a solution we went to using strtod to move the problem further out where it will probably not be an issue. strtod does properly convert the 15.00000000000 without error. 

snprintf:

snprintf(valueStr, 23, "%.6f", msg->val.valuef);

When the float value entered is 123456790519087104  (0x5bdb4da6) the string printed is 123456790519087076.187 . This is unexpected. We tried going to %.6lf and casting the float as double but that did not resolve issue like in the strtod case. 

Any thoughts on what might be causing this? It is important that the number entered is properly displayed or at least what numbers can be properly displayed and why they were not in this case.

Thanks,

Jennifer

  • Thank you for notifying us of this problem.  I can reproduce the same result.  I filed the entry EXT_EP-10042 to have this investigated.  You are welcome to follow it with the link below in my signature.

    Thanks and regards,

    -George

  • The fundamental issue here is that floating-point numbers have a binary format, and conversion between decimal and binary floating point has quite a few "gotchas."

    To understand what's going on here, you need to realize that (for example) 15e8 is exactly 0x59682f00. Now 32-bit floating-point only has 24 bits of precision, so we've already used up almost all of the precision just with the integer part. Algebraically, 15e9 is exactly 0x37e11d600, which exceeds the precision of 32-bit floating-point. The best we can do in 32-bit floating point is 0x37e11d400, which is 14999999488, or 0x37e11d800, which is 15000000512. The same holds when the decimal point is just after the "15" part of the number; only the number of significant digits in the binary representation matter. At first glance, it would seem that if 15 is exactly representable then adding more zeros would still give a representable number, but that's not the case, for the simple reason that 10 is not a power of two. Multiplying  by anything other than a power of two tends to increase the number of binary digits you need to represent the exact value.

    What you're seeing in the source code for strtof is the straightforward method for accumulating a floating-point value from a string: for each digit from left to right, multiply what you have by 10 and add the new digit, and only at the last moment set the exponent. That is, we compute 15.000000000 as 15,000,000,000 divided by one billion. You can see how this runs into the rounding problem noted above. Changing the algorithm to instead divide the addend by ever-increasing powers of ten gives you the same problem, only somewhere out to the right of the decimal point.  It would turn out better for this example, but not for others.

    It turns out that conversion from decimal to binary floating-point or the reverse is hard.  To get the very best answers from strtof (considering the string as a whole) requires quite sophisticated numerical methods. Our implementation does away with these methods for the sake of computing the result faster.

    If the precise value matters, you should consider expressing all of your floating-point constants in terms of hexadecimal floating point constants.  Because this kind of constant is a binary format, there is no roundoff problem as there is with decimal to binary conversion.  You can print hex floating-point numbers with the %a conversion.  For example, 123456790519087104 is exactly 0x1.b69b4cp+56