0

I have some json objects and when I convert them into dictionary in python they will rounded:

-112.07393329999999  ->  -112.0739333

My code is:

for line in open("c:\\myfile","r+").readlines():          
     d = json.loads(line)
     logtv = d['logtv']
steenslag
  • 79,051
  • 16
  • 138
  • 171
Mahdi
  • 967
  • 4
  • 18
  • 34
  • 2
    That's running into floating point issues. If you need to keep that level of precision, you can't use Python's built in float. – David Robinson Apr 22 '13 at 20:39
  • Duplicate of : http://stackoverflow.com/questions/7878341/python-dictionary-floats – Martin V. Apr 22 '13 at 20:40
  • 1
    You probably need to read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Fred Larson Apr 22 '13 at 20:40
  • possible duplicate of [Floating point inaccuracy examples](http://stackoverflow.com/questions/2100490/floating-point-inaccuracy-examples) – Aprillion Apr 22 '13 at 20:43
  • 1
    json's double `{"key": -112.07393329999999}` is converted to exactly the same bits as `{"key": -112.0739333}`. use `{"key": "-112.07393329999999"}` in the json if you want to preserve the string as it is and not convert the string into double – Aprillion Apr 22 '13 at 20:47
  • 2
    This is actually more about the python 2.7/3.1 feature "The repr() of a float x is shorter in many cases: it’s now based on the shortest decimal string that’s guaranteed to round back to x". – Pavel Anossov Apr 22 '13 at 20:50

2 Answers2

6

It's just a more compact representation of the same (binary, 64-bit) number.

In [12]: -112.07393329999999 == -112.0739333
Out[12]: True

In [17]: struct.pack('d', -112.0739333)
Out[17]: 've\xbcR\xbb\x04\\\xc0'

In [18]: struct.pack('d', -112.07393329999999)
Out[18]: 've\xbcR\xbb\x04\\\xc0'

If you want this exact decimal, there's no way to represent it as a number in JSON. You'll have to use strings in your JSON, Decimals/strings in your python and decimal fields in your DB.

 

SQL Server Floats are at most 64-bit (53-bit significand) as well.

Pavel Anossov
  • 60,842
  • 14
  • 151
  • 124
3

The answer is don't use floats. In most languages floats only have about 6 digits of significance and not too many more for doubles (note python floats are doubles). Use decimals if you know the exact precision. For JSON send it as a string or an int with an implied decimal point.

soap box: floats are very much overused. Floats should not be used by anything that you wouldn't represent with scientific notation, as that is what they really are underneath.

Note: Databases do not usually use floating point numbers, they use fixed point numbers. Which is exactly what a decimal is.

clarification

before you write the json file do something like

with  open("c:\\myfile","w") as my_file:
    for key in d:
        if isinstance(d[key], Decimal):
            d[key] = str(d[key])
    my_file.write(json.dumps(d))

then when reading the json, you can just put the value into the database as is or convert it back to Decimal if you need to work with it more.

cmd
  • 5,754
  • 16
  • 30
  • 1
    just to clarify, `-112.07393329999999` doesn't look like a 17 digits precision number, so decimals should be used BEFORE sending the number through json, not only when processing it like it is now – Aprillion Apr 22 '13 at 20:56
  • @deathApril right, my point was don't turn the value to float at any point. Decimals are great at getting generated strait from strings. – cmd Apr 22 '13 at 21:37
  • Not surprisingly, in Ruby the same problems occur and the proposed solutions are going in the same direction as Python's. It is even advocated that [Float is Legacy](http://www.slideshare.net/mrkn/float-is-legacy). – steenslag Apr 22 '13 at 22:35