在Python中处理非常小的数字

2024-06-01 11:47:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要乘以1e6个顺序为0.01的数。预期结果的顺序为1e-100000000。显然,典型的浮点运算无法处理这一问题。在

在网络上做了一些研究,我发现decimal library似乎可以解决这个问题。然而,它似乎有一些局限性,使它无法满足我的需要:

>>> Decimal('.01')**Decimal('1e5') # Seems to handle this
Decimal('1E-200000')
>>> Decimal('.01')**Decimal('1e5')*Decimal('1E200000') # Yeah! It works!
Decimal('1')
>>> Decimal('.01')**Decimal('1e6') # This result is strange...
Decimal('0E-1000026')
>>> Decimal('.01')**Decimal('1e6')*Decimal('0E1000026') # Wrong result
Decimal('0')

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


Tags: to网络顺序libraryitresultthisdecimal
2条回答

您的结果不正确,因为decimal也有精度(decimal是定点数学),所以这里也有下溢问题:

Decimal('.01')**Decimal('1e6')

Decimal('0E-1000026')

但是:

^{pr2}$

Decimal('1E-2000000')

您可以通过手动设置精度(如上述示例所示)或手动计算功率来解决您的问题,例如:

Decimal('.01')**Decimal('1e6')

可以转换为

Decimal('1e-2') ** Decimal('1e6')

以及后来

1 ** ((-2) ** 1e6) = 1 ** (-2000000)

Decimal module documentation

为什么不用对数呢?在

您需要计算:

RESULT  = x1 * x2 * x3 * x4 ... * xn

表示为:

^{pr2}$

如果存储自然对数,非常小的正数可以很好地存储到浮点数中:

^{3}$

不是存储数字本身,而是存储值的日志。在

假设您向自身添加ln(0.0000011)次。你得到大约-13815510.558。与float相比,作为float丢失的精度更小

不管你最后得到的是什么数字,你知道你的结果就是e的幂次。例如,RESULT = e^-13815510.558

您可以使用以下代码:

import math

class TinyNum:
    def __init__(self, other=None, *, pow=None):
        """
        x = TinyNum(0.0000912922)
        x = TinyNum("0.12345")     # strings are okay too
        x = TinyNum(pow = -110)    # e^-110
        y = TinyNum(x)             # copy constructor
        """
        if other:
            if isinstance(other, type(self)):
                self._power = other._power
            else:
                self._power = math.log(float(str(other)))
        else: # other == None
            self._power = float(str(pow))

    def __str__(self):
        return "e^"+str(self._power)

    def __mul__(lhs, rhs):
        rhs = type(lhs)(rhs)
        return type(lhs)(pow=lhs._power + rhs._power)

    def __rmul__(rhs, lhs):
        lhs = type(rhs)(lhs)
        return type(rhs)(pow=lhs._power + rhs._power)

    def __imul__(total, margin):
        total._power = total._power + type(total)(margin)._power


lyst = [
    0.00841369,
    0.004766949,
    0.003188046,
    0.002140916,
    0.004780032
]

sneaky_lyst = map(TinyNum, lyst)

print(math.prod(sneaky_lyst))

打印到控制台的消息是:

e^-27.36212057035477

相关问题 更多 >