【问题标题】:n**n**n heuristics in PythonPython中的n**n**n启发式
【发布时间】:2016-07-09 14:59:08
【问题描述】:

我只是在玩 Python 并发现了一个有趣的东西:我的电脑(i5,3 GHz)在尝试计算 10 ** 10 ** 10 几个小时后刚刚挂出。 我知道数学不是创建 Python 的目的,但我想知道没有办法帮助Python 计算它。

到目前为止,我的观察结果是:n ** (2** lg(n**n)) 的工作速度比 n ** n ** n 快 2 倍

n = 8 ** (8 ** 8)
n2 = 8 ** (2 ** 24)
# measured by timeit
> 4.449993866728619e-07
> 1.8300124793313444e-07

1) 有谁知道如何以最复杂的方式解决n ** n ** n

2) 生成器是否可以帮助减少内存滥用?

【问题讨论】:

  • 存储正整数 X 占用 O(log(X)) 空间。因此,如果 X = N^(N^N),它将占用 O((N^N) log N) 空间。

标签: python algorithm


【解决方案1】:

10 ** 10 ** 10 是一个非常非常大的数字。 Python 正在尝试分配足够的内存来表示该数字。 10.000.000.000(100 亿)位占用的内存比您的计算机一次性提供的内存要多得多,因此您的计算机现在正在将内存换出到磁盘以腾出空间,这就是为什么现在事情变得非常非常缓慢的原因。

为了说明,尝试在一些合适的数字上使用sys.getsizeof()

>>> import sys
>>> sys.getsizeof(10 ** 10 ** 6)
442948
>>> sys.getsizeof(10 ** 10 ** 7)
4429264

所以一个额外的数字需要大约 10 倍以上的内存。上面的数量是以字节为单位的,所以一个 100 万位的数字几乎需要 0.5 兆字节,1000 万位数字需要 4 兆字节。推断,您的号码将需要 4 GB 的内存。 Python 是否会获得那么多内存,这取决于您的操作系统和硬件。

Python 在现代平台上将整数存储在 increments of 30 bits 中;所以每 30 位需要额外的 4 字节存储空间。对于 100 亿位,归结为 (log2(10 ** 10 ** 10) / 30 * 4) / (1024 ** 3) == 大约 4.125GiB。

您不能使用 Python 来表示这么大的数字。甚至浮点数也达不到那么高:

>>> 10.0 ** 10 ** 10
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')

我对 Python 中的 bignum(大数)处理不太熟悉;也许gmpy libray 有工具来表示更好的数字。

【讨论】:

  • 如果我calculated 正确的话,几乎有 4GB 内存。
  • @arekolek:添加了更准确的计算。它超过 4GB,因为每 4 个字节只使用了 30 位。
  • 为了让您感受一下10**10**10 有多大,估计可观测宇宙中普通物质的数量“只有”10**10**1.72427 kg。
  • @MartijnPieters gmpy2 应该能够在具有 16+ GB RAM 的 64 位 Linux 系统上计算该值。直到稍后我才能测试实际的内存需求。不幸的是,当前可用的 Windows 版 gmpy2 失败了。
  • gmpy2 需要约 10 GB 的 RAM 和约 4 分钟来计算准确值。我快速估计了 Python 使用原生 long 类型计算准确值的运行时间 - 大约一周。
【解决方案2】:

如果整数精度不是最重要的,你可以使用float numbers

>>> 3**3**3
7625597484987
>>> 3.**3.**3.
7625597484987.0

但是,对于较大的值,它们将很快达到极限:

>>> 5.**5.**5.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

你可以通过decimal获得更高的分数:

>>> import decimal
>>> d = decimal.Decimal
>>> d(5)**d(5)**d(5)
Decimal('1.911012597945477520356404560E+2184')
>>> d(10)**d(10)**d(8)
Decimal('1.000000000000000000000000000E+100000000')

默认情况下,连那些都不能代表10**10**10

>>> d(10)**d(10)**d(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/decimal.py", line 2386, in __pow__
    ans = ans._fix(context)
  File "/usr/lib/python2.7/decimal.py", line 1676, in _fix
    ans = context._raise_error(Overflow, 'above Emax', self._sign)
  File "/usr/lib/python2.7/decimal.py", line 3872, in _raise_error
    raise error(explanation)
decimal.Overflow: above Emax

但这些限制并不固定。使用getcontext(),您可以将它们设置为任意大小:

>>> decimal.getcontext().Emax = 1000000000000
>>> d(10)**d(10)**d(10)
Decimal('1.000000000000000000000000000E+10000000000')

但请记住,这些数字并不是 100% 精确到最后一位(您的计算机可能甚至没有足够的内存存储每个数字),所以如果发生这种情况不要感到惊讶:

>>> d(10)**d(10)**d(10) == d(10)**d(10)**d(10) + 1000000
True

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 1970-01-01
    相关资源
    最近更新 更多