por*_*uod 5 python language-agnostic floating-point
以下python代码根据一些变量计算执行内容的迭代次数.
# a - b - c is always a multiple of d.
i = (a - b - c) / d
while i:
# do stuff
i -= 1
Run Code Online (Sandbox Code Playgroud)
这些变量都将是同一种类型的,即只有ints或floats或什么的.我担心的是,如果值是否可以正常工作floats.我知道足以始终考虑依赖于精确浮点值的陷阱.但我不知道上述情况是否危险.我可以使用i = int(round((a - b - c) / d)),但我很好奇了解更好的花车.
这一切都归结为以下几点:a - b - c是一个完全相同的d.因此,我依赖于(a-b-c)/d成为一个i可以减去的值1并在while循环中获得预期的迭代次数,隐含的假设i == 0变为真.也就是说,像这样的计算倍数可以递减1来恰好达到0吗?
我不仅要知道它是否不安全,更重要的是,我需要了解浮点数来解决这样的问题?如果有人果断地知道这是否安全,是否有可能解释如何?
您可以使用十进制模块来了解浮点数之间“隐藏”的内容,例如0.3:
>>> from decimal import Decimal
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
Run Code Online (Sandbox Code Playgroud)
请注意,Python 2.7 更改了浮点数的写入方式(repr(f)工作原理),因此它现在显示最短的字符串,如果您这样做,它将给出相同的浮点数float(s)。这意味着repr(0.3) == '0.3'在 Python 2.7 中,但repr(0.3) == '0.29999999999999999'在更早的版本中。我之所以提到这一点,是因为当您确实想了解数字背后的内容时,它可能会让事情变得更加混乱。
使用decimal模块,我们可以看到浮点数计算中的错误:
>>> (Decimal(2.0) - Decimal(1.1)) / Decimal(0.3) - Decimal(3)
Decimal('-1.85037170771E-16')
Run Code Online (Sandbox Code Playgroud)
这里我们可能期望(2.0 - 1.1) / 0.3 == 3.0,但是有一个小的非零差异。但是,如果您使用普通浮点数进行计算,那么您会得到零:
>>> (2 - 1.1) / 0.3 - 3
0.0
>>> bool((2 - 1.1) / 0.3 - 3)
False
Run Code Online (Sandbox Code Playgroud)
由于 1.85e-16 不为零,因此结果会在某个位置进行舍入:
>>> bool(-1.85037170771E-16)
True
Run Code Online (Sandbox Code Playgroud)
我不确定这个四舍五入到底发生在哪里。
至于一般的循环终止,我可以提供一个线索:对于小于 2 53的浮点数,IEEE 754 可以表示所有整数:
>>> 2.0**53
9007199254740992.0
>>> 2.0**53 + 1
9007199254740992.0
>>> 2.0**53 + 2
9007199254740994.0
Run Code Online (Sandbox Code Playgroud)
可表示的数字之间的间距为 2 从 2 53到 2 54,如上所示。但如果你i是一个小于 2 53的整数,那么i - 1也将是一个可表示的整数,你最终会命中0.0,这在Python中被认为是错误的。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |