【问题标题】:How to compute huge numbers with python?如何用python计算大量数字?
【发布时间】:2014-02-21 21:52:00
【问题描述】:

我目前正在尝试查找 x 的值,

x = (math.log(X) - math.log(math.fabs(p))/math.log(g))

与:

X = 53710695204323513509337733909021562547350740845028323195225592059762435955297110591848019878050853425581981564064692996024279718640577281681757923541806197728862534268310235863990001242041406600195234734872865710114622767319497082014412908147635982838670976889326329911714511434374891326542317244606912177994106645736126820796903212224

p = 79293686916250308867562846577205340336400039290615139607865873515636529820700152685808430350565795397930362488139681935988728405965018046160143856932183271822052154707966219579166490625165957544852172686883789422725879425460374250873493847078682057057098206096021890926255094441718327491846721928463078710174998090939469826268390010887

g = 73114111352295288774462814798129374078459933691513097211327217058892903294045760490674069858786617415857709128629468431860886481058309114786300536376329001946020422132220459480052973446624920516819751293995944131953830388015948998083956038870701901293308432733590605162069671909743966331031815478333541613484527212362582446507824584241

不幸的是,python 无法原生处理如此大的数字。

有人知道解决这个问题的方法吗?

感谢您的帮助。


编辑

因为很多你想知道我在做什么:

为了能够以安全的方式进行通信,Alice 和 Bob 继续进行 Diffie-Hellman 密钥交换。为此,他们使用质数 p :

p = 79293686916250308867562846577205340336400039290615139607865873515636529820700152685808430350565795397930362488139681935988728405965018046160143856932183271822052154707966219579166490625165957544852172686883789422725879425460374250873493847078682057057098206096021890926255094441718327491846721928463078710174998090939469826268390010887

还有整数g:

g = 73114111352295288774462814798129374078459933691513097211327217058892903294045760490674069858786617415857709128629468431860886481058309114786300536376329001946020422132220459480052973446624920516819751293995944131953830388015948998083956038870701901293308432733590605162069671909743966331031815478333541613484527212362582446507824584241

Alice 选择秘密数字 x,她计算 X=g^x mod p 并通过不安全的通道将 X 发送给 Bob。 Bob 选择秘密数字 y,他计算 Y=g^y mod p 并通过相同的不安全通道将 Y 发送给 Alice。 两者都可以计算出值 Z = X^y = Y^x = g^xy mod p

通过窥探通道,Charlie 检索到 X 和 Y 的值:

X = 53710695204323513509337733909021562547350740845028323195225592059762435955297110591848019878050853425581981564064692996024279718640577281681757923541806197728862534268310235863990001242041406600195234734872865710114622767319497082014412908147635982838670976889326329911714511434374891326542317244606912177994106645736126820796903212224

Y = 17548462742338155551984429588008385864428920973169847389730563268852776421819130212521059041463390276608317951678117988955994615505741640680466539914477079796678963391138192241654905635203691784507184457129586853997459084075350611422541722123509121359133932497700621300814065254996649070135358792927275914472632707420292830992294921992

这个练习的关键是z的值的md5sum

【问题讨论】:

  • 使用 Numpy 而不是 Python 来计算。
  • 结果和中间值是整数吗?大概不是,但是您的输入(特别是 p,并且您将 fabs 应用于其中之一...
  • 预期的答案是什么?
  • NumPy 不会比普通 Python 更好地处理这个问题。事实上,由于 long->float 转换处理不同,它会更快崩溃。
  • 如果它们是整数,python 确实 处理如此大的数字。任意大其实。如果你需要浮点数,你应该试试Decimal 模块,或者mpmath

标签: python numpy


【解决方案1】:

您可以使用 Decimal 库来做到这一点:

from decimal import Decimal

X = 53710695204323513509337733909021562547350740845028323195225592059762435955297110591848019878050853425581981564064692996024279718640577281681757923541806197728862534268310235863990001242041406600195234734872865710114622767319497082014412908147635982838670976889326329911714511434374891326542317244606912177994106645736126820796903212224
p = 79293686916250308867562846577205340336400039290615139607865873515636529820700152685808430350565795397930362488139681935988728405965018046160143856932183271822052154707966219579166490625165957544852172686883789422725879425460374250873493847078682057057098206096021890926255094441718327491846721928463078710174998090939469826268390010887
g = 73114111352295288774462814798129374078459933691513097211327217058892903294045760490674069858786617415857709128629468431860886481058309114786300536376329001946020422132220459480052973446624920516819751293995944131953830388015948998083956038870701901293308432733590605162069671909743966331031815478333541613484527212362582446507824584241
X=Decimal(X)
p=Decimal(p)
g=Decimal(g)

print X.ln() - abs(p).ln()/g.ln()

给予

769.7443428855116199351294830

【讨论】:

  • Vanilla python 给了我完全相同的结果。
  • Vanilla python 给出相同的结果,并且比十进制版本快大约 900 倍。在python 2.7
  • @LucasB -- "Vanilla" 对我来说不起作用,使用 Python 2.6.5。照原样抛出“OverflowError:long int too large to convert to float”。将“.0”添加到所有整数以预转换为浮点数不会导致异常,但会导致“nan”结果。
  • 澄清一下:香草python3.3使用math模块而不使用fabs,但abs因为fabs没有任何意义,因为OP告诉我们什么。
  • 致任何使用“vanilla Python”一词的人:如果在任何一种情况下都必须只导入一个 标准库 模块,那么一个比另一个更香草呢?
【解决方案2】:

Sympy 可能对您来说很有趣。您可以进行符号简化并调整您想要使用的精度(使用mpmath):

import sympy as sy
sy.init_printing() # enable pretty printing in IPython

# Build the expression:
X,p,g = sy.symbols('X,p,g')
expr = (sy.log(X) - sy.log(sy.Abs(p))/sy.log(g))
# expr = expr.simplify()  # doesn't have any benefit in this case

# The values:
vX = 53710695204323513509337733909021562547350740845028323195225592059762435955297110591848019878050853425581981564064692996024279718640577281681757923541806197728862534268310235863990001242041406600195234734872865710114622767319497082014412908147635982838670976889326329911714511434374891326542317244606912177994106645736126820796903212224
vp = 79293686916250308867562846577205340336400039290615139607865873515636529820700152685808430350565795397930362488139681935988728405965018046160143856932183271822052154707966219579166490625165957544852172686883789422725879425460374250873493847078682057057098206096021890926255094441718327491846721928463078710174998090939469826268390010887
vg = 73114111352295288774462814798129374078459933691513097211327217058892903294045760490674069858786617415857709128629468431860886481058309114786300536376329001946020422132220459480052973446624920516819751293995944131953830388015948998083956038870701901293308432733590605162069671909743966331031815478333541613484527212362582446507824584241

# substitute values into variables:
expr2 = expr.subs({X:vX, p:vp,g:vg})

# evaluate to 150 digits with internal precision up to 1000 digits:
print(expr2.evalf(n=150, maxn=1000))

给出结果:

    769.744342885511619935129482917192487900343653888850271462255718268257261969359878869753342583593581927254506121925469662801405523964742213571689617098

更新: 正如 casevh 和 David 所指出的,在使用 sympy 时,要注意不要因为使用普通浮点数作为输入而丢失准确性。为了澄清,让我们计算10**log10(10+1e-30),这显然导致10+1e-30:

import sympy as sy
import numpy as np

xf = 1e-30

# numpy with floats:
np_x1 = np.log10(10+ xf)
np_yf = 10**np_x1

# sympy with no extra benefit
sy1_x1 = sy.log(10 + xf) / sy.log(10)
sy1_ye = 10**sy1_x1
sy1_yf = sy1_ye.evalf(n=33)

# sympy, done right:
x = sy.symbols('x')
sy2_x1 = sy.log(10 + x) / sy.log(10)
sy2_ye = 10**sy2_x1
sy2_yf = sy2_ye.evalf(n=33, subs={x:xf})

print("correct answer: 10.0000000000000000000000000000010")
print("        numpy:  {:.31f}".format(np_yf))
print("  naive sympy:  " + repr(sy1_yf))
print("correct sympy:  " + repr(sy2_yf))

给出结果:

correct answer: 10.0000000000000000000000000000010
        numpy:  10.0000000000000000000000000000000
  naive sympy:  10.0000000000000017763568394002504
correct sympy:  10.0000000000000000000000000000010

【讨论】:

  • 将精度设置为 1000 并不能真正为您提供 1000 位的精度。真的,任何超过 16 岁的东西都是没有意义的。参考下面我的答案,其中引用了 sympy 文档。
  • 这个值其实是正确的。 evalf() 的输入值都是整数,因此不会因转换为 64 位浮点数而导致精度损失。
【解决方案3】:

numpy float64 dtype 的“机器 epsilon”约为 2.2e-16。这意味着您应该只期望结果中的前 16 位有效数字是准确的,除非您正在做一些非常棘手的事情(例如滚动您自己的自定义数据类型)。

Dietrich 建议使用 sympy 并设置较高的内部精度,但 sympy documentation 确认这不会逃避机器 epsilon 问题。

一些 Python 浮点数仅精确到大约 15 位作为输入,而其他的(分母是 2 的幂,例如 .125 = 1/4)是精确的。

换句话说,要非常小心处理与您一样大的数字所得到的结果,因为只要您使用 64 位浮点数进行数学运算,只有前 16 位有效数字才有意义。

【讨论】:

  • Dietrich 的答案完全正确,达到了指定的精度。您引用的句子仅适用于尝试对已转换为 Python 浮点数的值执行高精度计算。由于 evalf() 的输入是整数,因此不会损失精度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2019-04-24
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
相关资源
最近更新 更多