算术错误:Python 错误地划分变量

Posted

技术标签:

【中文标题】算术错误:Python 错误地划分变量【英文标题】:Arithmetic error: Python is incorrectly dividing variables 【发布时间】:2017-12-17 16:15:14 【问题描述】:

我得到的东西似乎没有多大意义。我正在通过编写一个小程序来练习我的编码,该程序可以让我在纸牌游戏的特定时间范围内获得某些卡片的概率。为了计算机会,我需要创建一个执行除法的方法,并将机会报告为分数和小数。所以我设计了这个:

from fractions import Fraction
def time_odds(card_count,turns,deck_size=60):
    chance_of_occurence = float(card_count)/float(deck_size)
    opening_hand_odds = 7*chance_of_occurence
    turn_odds = (7 + turns)*chance_of_occurence
    print ("Chance of it being in the opening hand: %s or %s" %(opening_hand_odds,Fraction(opening_hand_odds)))
    print ("Chance of it being acquired by turn %s : %s or %s" %(turns,turn_odds,Fraction(turn_odds) ))

然后我就这样使用它:

time_odds(3,5)

但无论出于何种原因,我都得到了这个答案:

"Chance of it being in the opening hand: 0.35000000000000003 or 
6305039478318695/18014398509481984"
"Chance of it being acquired by turn 5 : 0.6000000000000001 or 
1351079888211149/2251799813685248"

所以几乎是对的,只是小数点稍微偏离了一点,给出了 0.0000000000003 的差异或 0.0000000000000000000001 的差异。

当我让它像这样进行除法时,Python 不会这样做:

print (7*3/60)

这给了我 0.35,这是正确的。我可以观察到的唯一区别是,当我用变量而不是数字进行除法时,我得到的值稍微不正确。

我环顾四周寻找答案,大多数不正确的除法问题都与整数除法有关(或者我认为它可以称为地板除法),但我没有找到任何解决这个问题的方法。

当我对非常大的数字进行除法时,python 也遇到了类似的问题。怎么回事?

为什么会这样?我该怎么做才能纠正它?

【问题讨论】:

Why does the floating-point value of 4*0.1 look nice in Python 3 but 3*0.1 doesn't?的可能重复 另见(语言无关):***.com/questions/588004/… 你真的需要阅读这个(语言无关):docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 不能用二进制精确表示 【参考方案1】:

您看到的额外数字是浮点精度错误。随着您对浮点数进行越来越多的操作,错误有可能会复合。

当您尝试手动复制计算时看不到它们的原因是您的复制以不同的顺序执行操作。如果您计算7 * 3 / 60,则乘法首先发生(没有错误),并且除法引入了一个足够小的错误,Python 的float 类型将它隐藏在它的repr 中(因为0.35 明确地指的是相同的浮点值作为计算)。如果您执行7 * (3 / 60),则首先发生除法(引入错误),然后乘法将错误的大小增加到无法隐藏的程度(因为0.350000000000000030.35 的浮点值不同) .

为避免打印出可能是错误的额外数字,您可能需要明确指定将数字转换为字符串时使用的精度。例如,您可以使用%.3f,而不是使用%s 格式代码(在值上调用str),它会将您的数字四舍五入到小数点后三位。

您的Fractions 还有另一个问题。您正在直接从浮点值创建Fraction,它已经计算了错误。这就是为什么您看到分数打印出来的分子和分母非常大(它与不准确的数字完全相同漂浮)。如果您改为将整数分子和分母值传递给 Fraction 构造函数,它将为您简化分数,而不会出现任何浮点错误:

print("Chance of it being in the opening hand: %.3f or %s" 
      % (opening_hand_odds, Fraction(7*card_count, deck_size)))

这应该将数字打印为0.3507/20。你当然可以选择任何你想要的小数位数。

与浮点错误完全分开,计算实际上并没有得到正确的概率。您正在使用的公式可能足以让您在玩游戏时在脑海中进行操作,但它并不完全准确。如果您使用计算机为您计算数字,那么您不妨把它弄对。

D 抽牌后,从M 大小的牌组中抽到至少一张N 特定牌的概率为:

1 - (comb(M-N, D) / comb(M, D))

其中comb 是二进制系数或“组合”函数(在数学中通常称为“N 选择 R”并写为“nCr”)。 Python 在标准库中没有该函数的实现,但是您可能已经安装了许多附加模块,它们提供了一个,或者您可以很容易地编写自己的。请参阅this earlier question 了解更多详情。

对于您的示例参数,正确的赔率是“5397/17110”或0.315

【讨论】:

以上是关于算术错误:Python 错误地划分变量的主要内容,如果未能解决你的问题,请参考以下文章

如何划分两个 Prometheus 计数器

JDK8中JVM堆内存划分

JDK8中JVM堆内存划分

python 按行划分多变量

MVC架构的职责划分原则

软件工程-软件测试