Python While循环执行次数超出预期的原因及修正方案(投资翻倍计算场景)
我明白你遇到的问题了——这其实是浮点数精度误差在搞鬼,不是循环条件的逻辑问题!
问题本质解析
当初始投资是10美元、年利率2%时,理论上第35年的余额应该是 10*(1.02)^35 ≈ 20.00,但由于计算机用二进制存储浮点数,无法精确表示所有十进制小数,实际计算出来的newBalance在第35年时可能是一个略小于20的数(比如19.999999999999996)。这就导致循环条件newBalance < 20仍然成立,所以会多执行一次循环,到第36年才终止。
你尝试添加的newBalance != (2 * initialInvestment)完全起不到作用,因为浮点计算的结果几乎不可能精确等于20,这个判断相当于没加。
两种正确的解决方案
方案1:用epsilon抵消浮点误差
既然浮点数无法精确匹配,我们可以设置一个极小的阈值(比如1e-9,也就是0.000000001),当余额接近目标值(误差在阈值内)时就认为已经达标。修改后的代码如下:
initialInvestment = 10 intRate = 2 newBalance = initialInvestment years = 0 if initialInvestment > 0: target = 2 * initialInvestment # 用epsilon处理浮点精度问题 while newBalance < target - 1e-9: newBalance += (newBalance * (intRate/100)) years += 1 print(f'At {years} year(s), you would have ${newBalance:,.2f}') else: print(f'Please enter an investment amount greater than zero.') print(f'It would take {years} years to double your investment of ${initialInvestment:,.2f} at {intRate}%.')
这样当余额和目标值的差距小于1e-9时,就会终止循环,不会多执行一次。
方案2:使用精确的十进制计算(推荐用于金融场景)
如果是金融计算,追求精确性的话,建议用Python的decimal模块,它可以精确处理十进制小数,从根源上避免浮点误差:
from decimal import Decimal, getcontext # 设置足够的精度,满足投资计算需求 getcontext().prec = 10 initialInvestment = Decimal('10') intRate = Decimal('2') newBalance = initialInvestment years = 0 target = initialInvestment * 2 if initialInvestment > 0: while newBalance < target: newBalance += newBalance * (intRate / Decimal('100')) years += 1 print(f'At {years} year(s), you would have ${newBalance:.2f}') else: print(f'Please enter an investment amount greater than zero.') print(f'It would take {years} years to double your investment of ${initialInvestment:.2f} at {intRate}%.')
用Decimal类型存储数值后,计算结果会精确匹配理论值,循环会在第35年准确终止。
关于"years初始化为-1"的解释
把years初始化为-1后,循环里先执行years +=1再计算余额,相当于第一次循环后years是0,对应第1年的余额。当第35次循环后,余额达到目标值,years变成35,此时循环条件不满足,就会终止。这其实是一种“凑结果”的hack,没有解决根本的精度问题,遇到其他利率或初始金额时可能还是会出问题,所以不如上面两种方案靠谱。
内容的提问来源于stack exchange,提问作者imt

