2017-12-29 59 views
2

私は、1年以内に残高を支払うために最低限必要な最低限の支払いを行うことになっているコードを持っています。それはここでは(今のところ、私がテストしてきたように)772000000000000.なぜ数値が772000000000000以上であれば、私のPythonコードは無限ループになりますか?

までのすべての数字のために完璧に動作するコード(私がテストした数字は、その結果を以下の通り)である:私が言ったように

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と無限ループが発生しました。次の値をすべてAIRとして使用し、異なるAIRを使用して異なる値をテストすることで、数字によっても同様の結果が得られますが、次のようにすれば、何が起こっているのかを知ることができます:

6620 00000000000作品

771999999999999作品いくつかの時間後に何度も何度も

772000000000000繰り返し上位と下位

772100000000000作品いくつかの時間後に何度も何度も

772200000000000繰り返し上位と下位

772300000000000無限ループ

772400000000000 infini TEループ

772500000000000無限ループ

882100000000000無限ループ

999999999999999無限ループ

は自分でしようと気軽になぜこれが起こっている、私は完全に唖然ですか?

+0

それがうまくいった!あなたは聖人です、ありがとう!私はそれが起こることさえ知りませんでした。 – Cdhippen

答えて

3

floatを使用する場合は、すべての可能な10進数値を表すことはできないと考える必要があります。値が十分に大きくなると、2つの表現可能な浮動小数点値の差がご自分のしきい値をちょうど超える可能性があります。これは、値の間に「中間」浮動小数点が存在しないため、二等分線が進まない状況につながります。と例えば:

balance = float("772300000000000") 
annualInterestRate = float("0.2") 

それはで無限ループで終わる:

>>> 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の間に浮きがありません:だから

higher: 70368815315719.6 
lower: 70368815315719.58 

、のは、このビットを調べてみましょうしかし:

>>> b - a 
-0.015625 

これはあなたのしきい値よりも大きいです。だから無限ループにつながるループ間で何も変わることはありません。

しかし、あなたは簡単にarbitary精度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から来ている出力で/:私のコンピュータ上で、それは最終的に終了します。

+0

大変ありがとうございました。代わりにFraction()を使用して小数点を使用していたものをすべて変更し、最後に答えを浮動小数点に戻しました。 (私が無限を考慮する端末を打つまで、しかし、私は本当にそこに驚いていない)。 – Cdhippen

関連する問題