python - 如何在 python 中将超大数与超小数相乘?

标签 python numpy

我在做一些概率计算。
在我的一项任务中,我需要将从 10000 个项目中选择 8000 个样本的组合数乘以 0.8**8000。
组合数是一个长long-number,在numpy的帮助下,我得到0.8**8000的结果为5.2468172239242176864e-776.
但是当我尝试将这两个数字相乘时,我得到了 [9] 34845 segmentation fault ipython -i
那我该如何做这样的乘法呢?

PS:这是我的一段代码

import numpy
d2 = numpy.float128(0.8) ** 8000
d1 = 165555575235503558460892983752748337696863078099010763950122624527927836980322780662408249953188062227721112100054260160204180655980717428736444016909193193353770953722788106404786520413339850951599929567643032803416164290936680088121145665954509987077953596641237451927908536624592636591471456488142060812180933761408708169972797751139799352908109763166895772281109195968567911923343187466596002627570139321755043803267091330804414889831229832744256038117150720178689066894068507531026417815624234453195871008113238128934831837842040515600131726096039123279876153916504647241693083829553081901075278042326502699324012014817969085443550523855284341221708045253558716789811929298590803855947461554713178815399150688529048306222786951038548880400191620565711291586700534540755526276938422405001345270278335726581375322976014611332999126216550500951669985289322635729053541565465940744524663726205818866513444952048185208697438054246674199211750006230637806394882672053335493831407089830994135058867370833787098758113596190447219426121568324685764151601296948654893782399960327514764114467176417125060133454019708700782282480571935020898204763471121684913190735908414301826140125010936910161942130277906874552721346626800201093026689035996876035329180150478191582393837824731994055511844267891121846403164857127885959745644323971338513739214928092232132691519007718752719466750891748327404893783451436251805894736392433617289459646429204124129760273396235033220480921175386059331059354409267348067375581516003852060360378571075522650956157791058846993826792047806030332676423336065499519953076910418838626376480202828151673161942289092221049283902410699951912366163469099917310239336454637062482599733606299329923589714875696509548029668358723465427602758225427644633549944802010973352599970041918971524450218727345622721744933664742499521140235707102217164259438766026322532351208348119475549696983427008567651685921355966036780080415723688044325099562693124488758728102729947753752228785786200998322978801432511608341549234067324280214361346940194251357867820535466891356019219904248859277399657389914429390105240751239760865282709465029549690591863591028864648910033430400L
print d1 * d2

最佳答案

当将一个非常大的数字乘以一个非常小的数字时,使用 float 会带来巨大的不准确性。在您的情况下,数字的大小会导致溢出错误,因此您遇到的问题不仅仅是不准确!

每当您发现自己处于这种情况时,首先检查是否有可能留在整数域,然后先“按摩”一下数字会很有用。在您的情况下,这是可能的,我将在下面解释。

乘法的一个操作数,非常大的数,是 10000 个项目中的 8000 个样本。使用封闭式方程计算组合数,其中样本大小 n 为 10000,子集大小 r 为 8000。此处的感叹号 (!) 是阶乘,您可以在python的math.factorial中找到。

C(n,r) = n! / r! (n - r)!

另一个操作数 0.8 ** 8000 是极小的数,根据指数定律等于:

8**8000 / 10**8000

所以当我们将这两个数字相乘时,我们想要的答案是:

     10000! * 8**8000
--------------------------
 8000! * 2000! * 10**8000

让我们称这个数字为x,然后对两边取对数。在对数域中工作会将乘法转化为加法,将除法转化为减法,从而使事情更易于管理。

from math import log, factorial
numerator = log(factorial(10000)) + 8000*log(8)
denominator = log(factorial(8000)) + log(factorial(2000)) + 8000*log(10)
log_x = numerator - denominator

现在这些数字的数量级可以在 python 中使用。

您会发现 log_x 大约等于 3214。您现在只需观察 exp(log_x) == x 即可找到您的答案。这是一个非常大但有限的数字。

关于python - 如何在 python 中将超大数与超小数相乘?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33072998/

相关文章:

python - 无法在电子邮件中添加附件

python - 使用字符串指定 `from my_package import my_class as my_custom_name`

python - 从numpy中的3d数组中删除2d子数组

python - 将 pandas 数据框中出现的每个字符串值替换为单独的浮点值

python - 如何使用 OpenCV 平滑并变薄这些非常粗糙的图像?

Python修改和编辑列表

python - django:将 BadRequest 引发为异常?

python - 将列表的元素添加到某些列中的所有元素

python - 如何使用 python 提高解析器的速度?

python - 与复数相关的点积