【问题标题】:Accessing the highest digits of large numbers from Python long从 Python long 访问大数的最高位
【发布时间】:2012-11-25 00:53:08
【问题描述】:

我在 python 中处理数以万计的数字。 long 类型在对这些数字执行数学运算时效果很好,但是我无法以足够快的方式访问这些数字的最高位。请注意,我不确切知道该数字包含多少位数。 “最高位”是指最高位的数字,最低位可以使用模数快速访问。

我可以想到两种在 python 中访问这些数字的方法,但对于我的目的来说它们都太慢了。我尝试过转换为字符串并通过数组方法访问数字,但是当您有 10,000 多个数字时,类型转换很慢。或者,我可以简单地屏蔽位并截断,但这需要我知道 long 中有多少位。查找 long 中的位数需要在计数器上循环和掩码测试,这肯定会比字符串转换慢。

From the description here 似乎 long 类型实际上包含一个 bignum 数组。有什么方法可以访问存储 long 的底层数据结构,或者可能检查 long 从基本类型中有多少位?

如果人们有兴趣,我可以提供一个带有基准的示例。

【问题讨论】:

  • 如果你知道数量级,你可以除以10**(orderMag-1)。整数除法将为您提供最重要的数字
  • 位数未知。
  • 也许在 C 中使用 PyLong_AsVoidPtr 访问它,有趣的线程 gossamer-threads.com/lists/python/dev/…
  • 你需要十进制数字还是只需要位?
  • @AdamCadien: 那么你不能使用.bit_length() (Python 2.7+) 来获得不循环的位数然后右移吗?

标签: python long-integer bignum


【解决方案1】:

一种简单的方法,无需深入研究 long 类型的低级实现:

>>> n = 17**987273 # 1.2 million digits number

>>> digits = int(math.log10(n))

>>> k = digits - 24 # i.e. first 24 digits

>>> n / (10 ** k)
9953043281569299242668853L

在我的机器上运行得非常快。我试图得到这个数字的字符串表示,这需要很长时间。

对于 Python 3.x,请使用 n // (10 ** k)

这个大数字的一些时间(它快了 140 倍):

%timeit s = str(n)[:24]
1 loops, best of 3: 57.7 s per loop

%timeit n/10**(int(math.log10(n))-24)
1 loops, best of 3: 412 ms per loop


# With a 200K digits number (51x faster)

%timeit s = str(n)[:24]
1 loops, best of 3: 532 ms per loop

%timeit n/10**(int(math.log10(n))-24)
100 loops, best of 3: 10.4 ms per loop


# With a 20K digits number (19x faster)

%timeit s = str(n)[:24]
100 loops, best of 3: 5.4 ms per loop

%timeit n/10**(int(math.log10(n))-24)
1000 loops, best of 3: 272 us per loop

【讨论】:

  • 稍微修改的解决方案 bignum/10**(int(math.log10(bignum))-ndig)。使用 log10 是个好主意,但我发现这仅比 str 转换快一点,我仍然认为访问 bignum 数组会最快。
  • @AdamCadien 我的时间安排要快得多。我添加到答案中......顺便说一句,访问 bignum 数据可能会使您的代码不可移植。
  • 我在其他代码中发现效率低下,导致意外减速。 log10 解决方案效果很好!
【解决方案2】:

Python 2.7 对整数有 bit_length() 方法。

【讨论】:

    【解决方案3】:

    这是一个非常难看的一行,它将提取前几位小数:

    (x >> (x.bit_length()-50))*(10**(math.fmod((x.bit_length()-50)*math.log(2)/math.log(10), 1)))
    

    如果您的 x 值约为 10,000 位十进制数字,您应该得到一个精确到 12 位左右的答案。随着 x 变大,您的准确度会降低。

    如果你愿意使用外部模块,我会看gmpy2。 gmpy2 库提供对多精度整数和小数运算的 GMP(或 MPIR)库、多精度浮点运算的 MPFR 库和多精度复数运算的 MPC 库的访问。 gmpy2 整数比 Python 的原生 long 更快,您可以将 long 整数转换为浮点数以仅提取前导数字。上面的一个衬里就变成了:

    gmpy2.mpfr(x).digits()[0]
    

    即使数字变大,gmpy2 方法也会保持准确性。

    免责声明:我维护 gmpy2。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-24
      • 2015-11-01
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多