Why and how does python truncate numerical data?

社会主义新天地 提交于 2019-12-06 00:51:40

In general if you use '%.14f' % lat, you are LOSING PRECISION.

To get full precision from a float, use repr().

Example:

>>> lat = 1/3.
>>> lat
0.3333333333333333
>>> str(lat).count('3')
12
>>> ('%.14f' % lat).count('3')
14
>>> repr(lat).count('3')
16
>>>

By the way, you are using an old Python.

>>> 0.33245794180134 == 0.33245794180133997
True
>>>

Pythons before 2.7 produce repr(a_float) by using 17 significant decimal digits because that will guarantee that float(repr(a_float)) == a_float. The new method is to use the smallest number of digits that will provide the same guarantee. Follow this link and Ctrl-F search for repr().

If you are getting those numbers from an external source, then you could be losing precision by floating them and then serialising them with 14 decimal digits of precision.

If you are getting those numbers by calculation, then you could be losing precision by serialising them with 14 decimal digits of precision.

Summary: In general if you use '%.14f' % lat, YOU are losing precision -- not Python, not floating-point arithmetic, it's you..

You can try using string formatting to get desired precision.

>>> lat = 0.33245794180134
>>> lat
0.33245794180134
>>> "%.14f" % lat
'0.33245794180134'
>>> 

edit to incorporate comments:

>>> '{0:.14f}'.format(lat)
'0.33245794180134'
>>> 

str is for human-readable representations. It rarely produces something that's equivalent or similar to an expression that produces the value fed to it. repr, on the other hand, is explicitly for that. In fact, it's what the REPL uses to give feedback about the results of expressions.

Note though that floats are still of finite precision and can't represent certain numbers exactly, regardless of how you serialize them to strings.

The Decimal type from the python standard library decimal module is definitely what you want. It allows you to keep up 28 digits of precision by default but doesn't force numbers into a binary floating point representation. The Decimal type also allows for mathematical operations involving numbers of other types without requiring conversion.

Your example converted to Decimal:

>>> import decimal
>>> lat = decimal.Decimal(repr(0.33245794180134))
>>> long = decimal.Decimal(repr(32.57355093956))
>>> lat
Decimal('0.33245794180134')
>>> long
Decimal('32.57355093956')
>>> repr(lat)
'0.33245794180134'
>>> repr(long)
'32.57355093956'

Adding a number to a Decimal:

>>> lat + 2
Decimal('2.33245794180134')

Avoiding the imprecision of binary floating point representations of numbers like 1.1:

>>> onepointone = decimal.Decimal(repr(1.1))
>>> onepointone
Decimal('1.1')

The decimal module in the python standard library is a real math module rather than the approximation of math you get with traditional floating point representations and floating point processors. I wish it was the default because in the dictionary the approximation floating point math we get by default in most languages should be the first example of the definition of useless.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!