为什么不使用对数?
你想要计算:
RESULT = x1 * x2 * x3 * x4 ... * xn
将其表示为:
ln(RESULT) = ln(x1) + ln(x2) + ln(x3) + ln(x4) ... + ln(xn)
如果将非常小的正数存储为其自然对数,它们会很好地存储到浮点数中:
ln(0.000001) ≈ -13.81551
不要存储数字本身,而是存储这些值的对数。
假设您将ln(0.0000011)
加起来10^6
次。 您将得到大约-13815510.558
。 作为float
,与0.000001^(10^6)
相比,更少的精度会丢失。
无论您最终得到什么数字,您都知道您的结果只是该数字的指数。
例如,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:
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
math.frexp()
。取对数可能是最简单的方法,具体取决于你打算如何使用结果。 - President James K. Polk