【问题标题】:gmpy2 log2 not accurate after 16 digitsgmpy2 log2 16 位后不准确
【发布时间】:2016-01-08 15:18:38
【问题描述】:

在 gmpy2 中使用 log2() 时,在 16 位之后似乎不准确。它似乎在 15 位时工作正常,但之后使用 mpz(mpfr(2) ** mpfr(x)) 的答案不正确。我需要改变精度吗?我认为 python 本身可以精确到 53 位。

此外,gmpy2 中是否有一种方法可以在除 10 和 2 之外的基数中使用对数运算?例如,基数为 8 或 16。

【问题讨论】:

    标签: python math gmpy


    【解决方案1】:

    标准的 Python 浮点类型精确到 53 位,大约是 16 位十进制数字。 gmpy2 使用 53 位的默认精度。如果您想要更准确的结果,则需要提高精度。

    >>> import gmpy2
    >>> from gmpy2 import mpz,mpfr,log2
    >>> a=12345678901234567890
    >>> gmpy2.get_context().precision=70
    >>> mpz(2**log2(a))
    mpz(12345678901234567890L)
    

    要计算不同的对数,只需使用

    >>> gmpy2.log(x)/gmpy2.log(base)
    

    更新

    从一系列浮点计算中恢复精确的整数结果通常是不可能的。根据实际计算,您可以提高精度,直到“足够接近”。

    让我们看看精度的影响。请注意,a 的长度为 57 位,因此无法用 53 位的浮点精度精确表示。

    >>> a=123543221556677776
    >>> a.bit_length()
    57
    >>> gmpy2.get_context().precision=53
    >>> mpfr(a);2**log2(a)
    mpfr('1.2354322155667778e+17')
    mpfr('1.2354322155667752e+17')
    

    由于二进制浮点数到十进制数的转换会引入转换错误,让我们看看二进制的结果。

    >>> mpfr(a).digits(2);(2**log2(a)).digits(2)
    ('11011011011101001111001111100101101001011000011001001', 57, 53)
    ('11011011011101001111001111100101101001011000010111001', 57, 53)
    

    让我们尝试将精度提高到 57 位。

    >>> gmpy2.get_context().precision=57
    >>> mpfr(a).digits(2);(2**log2(a)).digits(2)
    ('110110110111010011110011111001011010010110000110010010000', 57, 57)
    ('110110110111010011110011111001011010010110000110010011000', 57, 57)
    

    请注意更多位是正确的,但仍然存在错误。让我们试试 64 位。

    >>> gmpy2.get_context().precision=64
    >>> mpfr(a);2**log2(a)
    mpfr('123543221556677776.0',64)
    mpfr('123543221556677775.953',64)
    >>> mpfr(a).digits(2);(2**log2(a)).digits(2)
    ('1101101101110100111100111110010110100101100001100100100000000000', 57, 64)
    ('1101101101110100111100111110010110100101100001100100011111111010', 57, 64)
    

    大量尾随 1 大致相当于十进制尾随 9。

    一旦“足够接近”,您就可以转换为整数,将结果四舍五入为预期值。

    为什么 57 位不够用? gmpy2 使用的 MPFR 库确实执行正确的舍入。仍然有一个小错误。让我们也看看使用正确舍入值上方和下方的浮点值的结果。

    >>> gmpy2.get_context().precision=57
    >>> b=log2(a)
    >>> 2**gmpy2.next_below(b);2**log2(a);2**gmpy2.next_above(b)
    mpfr('123543221556677746.0',57)
    mpfr('123543221556677784.0',57)
    mpfr('123543221556677822.0',57)
    

    请注意,即使b 的微小变化也会导致2**b 发生更大的变化。

    更新 2

    浮点运算只是对实数数学性质的近似。有些数字是有理数(它们可以写成分数),但大多数数字是无理数(它们永远不能完全写成分数)。浮点运算实际上使用数字的有理逼近。

    我跳过了下面的一些细节 - 我假设所有数字都在 0 和 1 之间。

    对于二进制浮点(大多数计算机使用的),有理逼近的分母必须是 2 的幂。像 1/21/4 这样的数字可以精确表示。十进制浮点数使用分母为 10 次方的有理近似值。1/2、'1/4'、'1/5' 和 1/20 等数字都可以精确表示。两者都不能准确地代表1/3。浮点运算的 base-6 实现可以精确地表示 1/21/3,但不能表示 1/10。特定格式的精度仅指定分子的最大大小。总会有一些有理数不能用给定的基数精确表示。

    由于无理数不能写成有理数,它们不能用给定的基数精确表示。由于对数和指数函数几乎总是产生无理值,因此计算几乎永远不会精确。通过提高精度,您通常可以“足够接近”,但永远无法准确。

    有些程序可以使用symbolically - 它们会记住alog2(n),当您使用2**a 时,会返回a 的确切值。见SymPy

    【讨论】:

    • 我将精度提高到 100,但输出似乎不起作用,除非我使用您提供的代码。如果我尝试使用该输出,则示例 log2 (123543221556677776) 以 mpfr ('56.777793469605039610459389190493', 100) 结尾,它与原始输出不匹配。使用具有相同编号的代码可以正常工作。精度是否必须与求解方程所需的确切位数相匹配?
    • 我不明白“使用该输出”是什么意思。你能显示你正在尝试的确切命令吗?
    • Log2 (x),我将输出复制并粘贴到 mpz (mpfr (2)**mpfr (y)) 中。 x 是一个大于 16 位的数字,y 是我从输出中复制和粘贴的内容。我尝试将其用于数学作业,我可以只使用 log2 () 的输出是正确的。它似乎只在内存中正确,而不是在 python 解释器的输出中。
    • log2(x) 提供的值有多准确?您需要在整个计算过程中保持一致的精度,并在需要时提高精度。我编辑了答案以包含更多示例。
    • 我真的很抱歉一直在讨论这个问题。不可能得到准确的答案吗?这是数学问题还是图书馆问题?我对数学不是很擅长,但我一直在研究不同的数字基数和针对不同数字基数的论据,这些数字基数可以解决这个问题,比如打数或基数 6 而不是基数 10。考虑到处理器默认情况下的工作方式,我真的很喜欢基数 16。我想在不写 ..33333333 之类的东西的情况下回答我的作业。我说得有道理吗?
    猜你喜欢
    • 2021-11-12
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多