7

我正在尝试在 Python 中划分一些大数,但我得到了一些奇怪的结果

NStr = "7D5E9B01D4DCF9A4B31D61E62F0B679C79695ACA70BACF184518" \
       "8BDF94B0B58FAF4A3E1C744C5F9BAB699ABD47BA842464EE93F4" \
       "9B151CC354B21D53DC0C7FADAC44E8F4BDF078F935D9D07A2C07" \
       "631D0DFB0B869713A9A83393CEC42D898516A28DDCDBEA13E87B" \
       "1F874BC8DC06AF03F219CE2EA4050FA996D30CE351257287" 

N = long(NStr, 16)
f2 = 476

fmin = N / float(f2)

print N - (fmin * float(f2))

0.0按预期输出。但是,例如,如果我将代码更改为

fmin = N / float(f2)
fmin += 1

我仍然得到输出0.0

我也尝试使用十进制包

fmin = Decimal(N) / Decimal(f2)
print Decimal(N) - (fmin * Decimal(f2))

但这给了我一个输出-1.481136900397802034028076389E+280

我假设我没有告诉 python 如何正确处理大量数字,但我不知道从哪里开始。

我还应该补充一点,最终目标是计算

fmin = ceil(N / float(f2))

尽可能长且准确

4

6 回答 6

7

扩展我的评论,如果和Ns严格大于 0,那么f2long

 fmin = (N - 1) // f2 + 1

完全正确ceil(N / float(f2))(但比使用浮点数更准确)。

(使用//而不是/整数除法是为了与 Python 3.x 兼容,无需额外的努力。)

这是因为N // f2给你(基本上)floor(N / float(f2)),所以N // f2 + 1几乎总是和ceil. 但是,whenN是 , 的倍数f2太大N // f2 + 1+1不应该存在),但使用可以N - 1解决此问题,并且不会破坏另一种情况。

(这对任何一个都不起作用Nf2小于或等于0,但可以单独处理)

于 2012-04-12T11:07:27.043 回答
4

fminfloat在您将长整数除以浮点数之后。它的值为1.84952718165824e+305。加1根本不会改变它,精度根本不高。

如果您改为进行整数除法,则fmin仍然是long

>>> fmin = N / f2
>>> fmin
18495271816582402193321106509793602189617847415669131056768139225220221855498293
49983070478076000952025038039460539798061570960870927236986153971731443029057201
52035339202255934728764897424408896865977423536890485615063959262845076766281553
766072964756078264853041334880929452289298495368916583660903481130L
>>> N - (fmin * f2)
111L

当然,您不会0因为整数除法而丢弃结果的小数部分。但现在,加 1有所不同:

>>> N - ((fmin+1) * f2)
-365L

使用该Decimal模块不会改变问题:

>>> from decimal import Decimal, getcontext
>>> fmin = Decimal(N) / Decimal(f2)
>>> fmin
Decimal('1.849527181658240219332110651E+305')

仍然没有无限的精度,即使你设置Decimal.getcontext().prec = 2000了,你仍然不会得到精确的 0。

于 2012-04-12T10:43:43.123 回答
3

如果您需要精度,请完全避免浮点运算。由于 python 具有任意精度整数,您可以使用基本整数算术计算除法的上限。假设除数和除数都是正数,这样做的方法是在除法之前将除数 - 1 添加到除数。在你的情况下:

fmin = (N + f2 - 1) / f2

在 Python 3.x 上,使用//运算符而不是/获取整数除法。

于 2012-04-12T11:28:18.827 回答
2

Fraction来自fractions模块可能有用:

>  : N = Fraction(N)   
>  : f2 = Fraction(f2)
>  : fmin = N / f2
>  : print N-f2*fmin
0
>  : fmin += 1
>  : print N-f2*fmin
-476

但是,如果您的唯一目标是计算ceil(N / float(f2)),您可以使用:

>  : fmin = N/f2 + int(ceil((N % f2) / float(f2)))
>  : print fmin
184952718165824021933211065097936021896178474156691310567681392252202218554982934998307047807600095202503803946053979806157096087092723698615397173144302905720152035339202255934728764897424408896865977423536890485615063959262845076766281553766072964756078264853041334880929452289298495368916583660903481131
于 2012-04-12T11:06:05.873 回答
1

对于这种操作,浮点数根本没有足够的精度。

您可以使用 提高decimal模块的精度getcontext()。例如使用 65536 位小数:

from decimal import Decimal, getcontext
getcontext().prec = 2**16

然后:

>>> print Decimal(N) - (fmin * Decimal(f2))
-2E-65228

仍然不是 0 而是更接近 :)

请参阅此答案ceil()Decimal对象执行操作。

于 2012-04-12T10:50:32.557 回答
1

我还在 python 2.7.2 中发现了类似的行为:

In [17]: N
Out[17]: 8803749384693223444020846698661754642258095369858506383021634271204825603217187705919415475641764531639181067832169438773077773745613648054092905441668
8183122792368821460273824930892091174018634908205253603559871152770444609114256540750019592650731223893254070047675403322419289706083795604293822590057017991L

In [18]:

In [18]: (fmin * float(f2))
Out[18]: 8.803749384693223e+307
In [19]: N - (fmin * float(f2))
Out[19]: 0.0

In [20]: (fmin * float(f2))
Out[20]: 8.803749384693223e+307

In [21]: N == (fmin * float(f2))
Out[21]: False

In [22]: N < (fmin * float(f2))
Out[22]: False

In [23]: N > (fmin * float(f2))
Out[23]: True

由于我不明白的原因,似乎从 long 中减去 float 会产生 0。

解决方案似乎是将两者都转换为decimal.Decimal

In [32]: decimal.Decimal(N) - decimal.Decimal(fmin * float(f2))
Out[32]: Decimal('4.099850360284731589507226352E+291')
于 2012-04-12T10:52:52.540 回答