在Python中划分大数字

时间:2012-04-12 10:34:36

标签: python

我试图在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))

尽可能长且准确

6 个答案:

答案 0 :(得分: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,你仍然不会得到正好的。{/ p>

答案 1 :(得分:4)

扩展我的评论,如果Nf2 long严格大于0,那么

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

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

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

这是因为N // f2为您提供(基本上)floor(N / float(f2)),因此N // f2 + 1几乎总是与ceil相同。但是,当Nf2的倍数时,N // f2 + 1太大(+1不应该存在),但使用N - 1修复此问题,不打破其他情况。

(这不适用于Nf2小于或等于0,但可以单独处理)

答案 2 :(得分:3)

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

fmin = (N + f2 - 1) / f2

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

答案 3 :(得分:1)

Floats只是没有足够的精度来进行这种操作。

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

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

然后:

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

仍然不是0但更接近:)

this answerceil()对象上执行Decimal

答案 4 :(得分: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

由于我不明白的原因,似乎从长期减去浮点数会产生0。

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

In [32]: decimal.Decimal(N) - decimal.Decimal(fmin * float(f2))
Out[32]: Decimal('4.099850360284731589507226352E+291')

答案 5 :(得分:1)

来自fractions模块的

Fraction可能很有用:

>  : 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