python为什么以及如何截断数值数据?

时间:2011-04-20 10:40:35

标签: python serialization floating-accuracy

我在这里处理两个变量,但是因为当我想将它们作为URL参数发送时它们的值似乎正在改变(它们松散的精度)而感到困惑。

看看这个场景,我在这里从python解释器重现它:

>>> lat = 0.33245794180134
>>> long = 32.57355093956
>>> lat
0.33245794180133997
>>> long
32.57355093956
>>> nl = str(lat)
>>> nl '0.332457941801'
>>> nlo = str(long)
>>> nlo '32.5735509396'

那发生了什么?我如何确保在将latlong序列化为字符串并将其作为网址查询字符串的一部分发送时,我不会失去其精确的精确度?

澄清情况:

  1. 数据最初作为浮动(在集合中)来自另一个从计算中创建它们的模块。
  2. 精确度是一个敏感问题,因为此数据用于跟踪和监控排序,错误的值可能会导致误报或不必要的警报。
  3. 没有办法将数据发送到目标引擎(通过一个狡猾的api监听)而不将数据序列化为字符串(所以我可以将它们作为参数放在查询字符串中)
  4. 所以我需要的是将浮点数转换为字符串的最佳方法,同时将精度/信息损失降至最低。

4 个答案:

答案 0 :(得分:4)

一般情况下,如果您使用'%.14f' % lat,则失去精确度

要从浮点数中获得完全精度,请使用repr()

示例:

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

顺便说一句,你使用的是旧的Python。

>>> 0.33245794180134 == 0.33245794180133997
True
>>>

2.7之前的蟒蛇通过使用17个有效十进制数来产生repr(a_float)因为这将保证float(repr(a_float)) == a_float。新方法是使用最小数量的数字来提供相同的保证。按照this link和Ctrl-F搜索repr()

如果你从外部源获取这些数字,那么你可能会通过浮动它们然后用精确的14位十进制数字序列化来丢失精度。

如果您通过计算获得这些数字,那么您可能会通过将它们精确到14位十进制数字而失去精确度。

总结:一般来说,如果你使用'%。14f'%lat,正在失去精度 - 不是Python,不是浮点运算,那就是你......

答案 1 :(得分:3)

您可以尝试使用字符串格式来获得所需的精度。

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

修改以合并评论:

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

答案 2 :(得分:2)

str用于人类可读的表示。它很少产生与产生馈送给它的值的表达式等价或相似的东西。另一方面,repr是明确的。实际上,这是REPL用来提供有关表达式结果的反馈的内容。

注意虽然浮点数仍然具有有限的精度,并且不能精确地表示某些数字,无论您如何将它们序列化为字符串。

答案 3 :(得分:0)

python标准库十进制模块中的Decimal类型绝对是您想要的。它允许您默认保持28位精度但不强制数字为二进制浮点表示。 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'

将数字添加到十进制:

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

避免数字的二进制浮点表示不精确,如1.1:

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

python标准库中的十进制模块是一个真正的数学模块,而不是传统浮点表示和浮点处理器的数学近似。我希望它是默认值,因为在字典中我们默认在大多数语言中得到的近似浮点数学应该是无用定义的第一个例子。