0

I'm having some problems with precision when importing floats from csv files created in Python to a program written in C. The following code is an example of what happens in my program: Python writes a float32 value to a file (in this case 9.8431373e+00), I read it into a string and use strtof to convert it back into float32, but the result is different on the last decimal place.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    
    char* a;
    char x[10] = "9.8431373";
    printf("%s\n", x);
    float f = strtof(x,&a);
    printf("%.7e\n", f);
}

Output:

9.8431373
9.8431377e+00

Now, correct me if I am wrong, but a float object in C has 32 bits which leads to 7 decimal places of precision after wherever its floating point is. So there shouldn't be any precision errors if I'm not declaring a number bigger than the float allows.

If I did indeed declare a number more precise than the float in C allows, then how has Python accepted "9.8431373e+00" as a Float32 without correcting it? Does Python and C have different standards for 32-bit floats?

Ricardo
  • 65
  • 5
  • 2
    No, 7 *significant* digits. Not decimal places. Your `9.8431373` has 8 significant digits. – Weather Vane Oct 19 '21 at 22:15
  • A `float` has a 23 bit mantissa which can take any one of 8388608 values, so that's 6 full digits of precision, and a partial 7th digit. So you actually got *more* matching digits than expected. – user3386109 Oct 19 '21 at 22:16
  • @WeatherVane Oh, so that accounts for the 9 in "9.8431373"? That makes sense. But then how did Python managed to store a float32 with that value? – Ricardo Oct 19 '21 at 22:18
  • I don't know Python, and you haven't shown that anyway, but you mentioin storing as a string. C won't object if you provide more precision than can be accurately held. – Weather Vane Oct 19 '21 at 22:21
  • @WeatherVane The Python part of the problem has been answered, but I wanted to make sure then that if this time I write a number with 7 significant digits like "9.843137" there won't cause any more precision problems, is this correct? Or do I have to decrease yet another digit? – Ricardo Oct 19 '21 at 22:42
  • As [mentioned](https://stackoverflow.com/questions/69638183/python-to-c-floating-point-imprecision?noredirect=1#comment123089900_69638183) 6 figures is guaranteed, maybe 7 available. If you want to be sure use `double.` In general I would say never use `float` unless there is a very good reason why you can't use `double`. – Weather Vane Oct 19 '21 at 22:55

2 Answers2

3

Python interprets as double by default. You would see the same issue in Python if you packed to single precision and unpacked again:

>>> import struct
>>> a = struct.pack('<f', 9.8431373)
>>> b, = struct.unpack('<f', a)
>>> b
9.843137741088867
Passerby
  • 808
  • 1
  • 5
  • 9
  • Ah, I see. I was confused because Python described the arrays as "float32" but if those were doubles that makes more sense. – Ricardo Oct 19 '21 at 22:20
1

Fundamentally, the decimal fraction 9.8431373 does not exist in binary floating-point, either single (float) or double precision. As a 32-bit float the closest you can get is a binary number that's equivalent to about 9.84313774, and as a double the closest you can get is a number corresponding to about 9.8431373000000004.

It's up to some combination of you, and your programming language, how these numbers get displayed back to you in decimal. Sometimes they're rounded, sometimes they're truncated. I don't know that much about Python, but I know that its rules are at least a little bit different from C's, so I'm not surprised you're seeing last digits that are off by 1.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • The relevant rules are: (1) Python's `float` is equivalent to C's `double`, and (2) Python's default output format uses the minimum number of digits so that conversion from `float` to `str` to `float` always gives the original value. – dan04 Oct 20 '21 at 19:45