如果数字大于或等于 772000000000000,为什么我的 python 代码会产生无限循环?
Why does my python code produce an infinite loop if the number is larger than or equal to 772000000000000?
我有一个代码可以计算出您在一年内还清余额所需支付的最低月付款额。它适用于所有数字,直到(据我测试)772000000000000。
这是代码(我测试过的数字及其结果如下):
import time
balance = float(input("balance: "))
annualInterestRate = float(input("AIR: "))
# formulas for lower and higher binding for bisectional search
monthlyInterestRate = annualInterestRate / 12
lower = balance / 12
higher = (balance * (1 + monthlyInterestRate) ** 12) / 12
while True:
guess = ((higher - lower) / 2 + lower)
print('higher: %s' % higher)
print('lower: %s' % lower)
remaining = balance
for i in range(12):
unpaid = remaining - guess
remaining = unpaid + monthlyInterestRate*unpaid
if higher - lower <= .01 and remaining < 0:
result = lower
print("Lowest Payment: %s" % result)
break
elif higher - lower <= .01 and remaining >= 0:
result = higher
print("Lowest Payment: %s" % result)
break
elif remaining < -0.01:
higher = guess
print("remaining: %s" % remaining)
print(guess)
print('too high')
time.sleep(.5)
elif remaining > 0:
lower = guess
print("remaining: %s" % remaining)
print(guess)
print('too low')
time.sleep(.5)
正如我所说,这为我测试的每个数字提供了正确的结果,但后来我测试了 999999999999999 并且我得到了一个无限循环,我通过测试以下值来缩小问题开始发生的范围,所有这些值都使用 .2 作为AIR,使用不同的 AIR 可以产生不同但相似的结果,具体取决于数量,但以下内容应该让您对发生的事情有一个很好的了解:
662000000000000 作品
771999999999999 作品
772000000000000 一段时间后一遍又一遍地重复上升和下降
772100000000000 作品
772200000000000 一段时间后一遍又一遍地重复上升和下降
772300000000000 无限循环
772400000000000 无限循环
772500000000000 无限循环
882100000000000无限循环
999999999999999无限循环
你自己试试吧,我完全傻眼了,为什么会这样?
如果您使用 float
s,您必须考虑这些不能代表所有可能的十进制值。如果值足够大,两个可表示的浮点值之间的差异可能会超过您的阈值。这会导致平分无法进行的情况,因为值之间没有 "middle" 浮动。例如:
balance = float("772300000000000")
annualInterestRate = float("0.2")
它以无限循环结束:
higher: 70368815315719.6
lower: 70368815315719.58
所以,让我们稍微检查一下:
>>> a = 70368815315719.6
>>> b = 70368815315719.58
>>> import numpy as np
>>> np.nextafter(a, 0) == np.float64(b)
True
>>> np.nextafter(b, np.inf) == np.float64(a)
True
所以 a
和 b
之间没有浮动,但是:
>>> b - a
-0.015625
所以这比你的阈值大。所以在循环之间没有任何变化会导致无限循环。
但是,您可以使用任意精度轻松解决此问题 Fraction
:
from fractions import Fraction
balance = Fraction("772300000000000")
annualInterestRate = Fraction("0.2")
... # rest of your code
代码中的所有操作都保留了 Fraction
(如果您使用了 math
函数或 **
它可能会有所不同)并且至少在我的计算机上它最终以:
higher: 161683724083791631395206486083981108997/2297661589986627614146560
lower: 41391033365450653948925712865241263190149/588201367036576669221519360
Lowest Payment: 161683724083791631395206486083981108997/2297661589986627614146560
请注意来自 Fraction
的输出中的 /
。
我有一个代码可以计算出您在一年内还清余额所需支付的最低月付款额。它适用于所有数字,直到(据我测试)772000000000000。
这是代码(我测试过的数字及其结果如下):
import time
balance = float(input("balance: "))
annualInterestRate = float(input("AIR: "))
# formulas for lower and higher binding for bisectional search
monthlyInterestRate = annualInterestRate / 12
lower = balance / 12
higher = (balance * (1 + monthlyInterestRate) ** 12) / 12
while True:
guess = ((higher - lower) / 2 + lower)
print('higher: %s' % higher)
print('lower: %s' % lower)
remaining = balance
for i in range(12):
unpaid = remaining - guess
remaining = unpaid + monthlyInterestRate*unpaid
if higher - lower <= .01 and remaining < 0:
result = lower
print("Lowest Payment: %s" % result)
break
elif higher - lower <= .01 and remaining >= 0:
result = higher
print("Lowest Payment: %s" % result)
break
elif remaining < -0.01:
higher = guess
print("remaining: %s" % remaining)
print(guess)
print('too high')
time.sleep(.5)
elif remaining > 0:
lower = guess
print("remaining: %s" % remaining)
print(guess)
print('too low')
time.sleep(.5)
正如我所说,这为我测试的每个数字提供了正确的结果,但后来我测试了 999999999999999 并且我得到了一个无限循环,我通过测试以下值来缩小问题开始发生的范围,所有这些值都使用 .2 作为AIR,使用不同的 AIR 可以产生不同但相似的结果,具体取决于数量,但以下内容应该让您对发生的事情有一个很好的了解:
662000000000000 作品
771999999999999 作品
772000000000000 一段时间后一遍又一遍地重复上升和下降
772100000000000 作品
772200000000000 一段时间后一遍又一遍地重复上升和下降
772300000000000 无限循环
772400000000000 无限循环
772500000000000 无限循环
882100000000000无限循环
999999999999999无限循环
你自己试试吧,我完全傻眼了,为什么会这样?
如果您使用 float
s,您必须考虑这些不能代表所有可能的十进制值。如果值足够大,两个可表示的浮点值之间的差异可能会超过您的阈值。这会导致平分无法进行的情况,因为值之间没有 "middle" 浮动。例如:
balance = float("772300000000000")
annualInterestRate = float("0.2")
它以无限循环结束:
higher: 70368815315719.6
lower: 70368815315719.58
所以,让我们稍微检查一下:
>>> a = 70368815315719.6
>>> b = 70368815315719.58
>>> import numpy as np
>>> np.nextafter(a, 0) == np.float64(b)
True
>>> np.nextafter(b, np.inf) == np.float64(a)
True
所以 a
和 b
之间没有浮动,但是:
>>> b - a
-0.015625
所以这比你的阈值大。所以在循环之间没有任何变化会导致无限循环。
但是,您可以使用任意精度轻松解决此问题 Fraction
:
from fractions import Fraction
balance = Fraction("772300000000000")
annualInterestRate = Fraction("0.2")
... # rest of your code
代码中的所有操作都保留了 Fraction
(如果您使用了 math
函数或 **
它可能会有所不同)并且至少在我的计算机上它最终以:
higher: 161683724083791631395206486083981108997/2297661589986627614146560
lower: 41391033365450653948925712865241263190149/588201367036576669221519360
Lowest Payment: 161683724083791631395206486083981108997/2297661589986627614146560
请注意来自 Fraction
的输出中的 /
。