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

时间:2017-07-13 03:57:26

标签: python math division

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

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.000000000000000000001差异。

当我按照这样划分它时,Python不会这样做:

print (7*3/60)

这只给我0.35,这是正确的。我能观察到的唯一区别是,当我用变量而不是数字划分时,我得到的值略有不正确。

我已经四处寻找答案了,大多数错误的划分问题都与整数划分有关(或者我认为它可以称为地板划分),但我没有设法找到任何东西解决这个问题

当我划分真正的大数字时,我遇到了与python类似的问题。发生了什么事?

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

1 个答案:

答案 0 :(得分:3)

您看到的额外数字是浮点精度错误。当您使用浮点数进行越来越多的操作时,错误有可能复合。

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

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

您的Fraction还有另一个问题。您直接从浮点值创建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。您当然可以选择任意数量的小数位。

完全与浮点错误分开,计算实际上没有正确的概率。你正在使用的公式可能足以让你在玩游戏时做到这一点,但它并不完全准确。如果您正在使用计算机来为您处理数字,那么您也可以做对。

N抽取后,从M尺寸的牌组中抽取至少一张D张特定牌的概率为:

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

其中comb是二进制系数或"组合"功能(通常用" N选择R"和写'&34; nCr"在数学中)。 Python在标准库中没有该函数的实现,但是你可能已经安装了很多可以提供的模块,或者你可以很容易地编写自己的模块。有关详细信息,请参阅this earlier question

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