如果数字大于或等于772000000000000,为什么我的python代码会产生无限循环?

时间:2017-12-29 20:58:14

标签: python python-3.x while-loop floating-point edx

我有一个代码,该代码应该产生您在一年内支付余额所需的最低月付款。它适用于所有数字,直到(据我测试过)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无限循环

随意尝试一下,我完全傻到为什么会发生这种情况?

1 个答案:

答案 0 :(得分:3)

如果使用float s,则必须考虑这些不能代表所有可能的十进制值。如果值足够大,则两个可表示的浮点值之间的差异可能会超过您的阈值。这导致了二分法不能进展的情况,因为没有中间的&#34;在值之间浮动。例如:

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

所以ab之间没有浮动,但是:

>>> 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