我希望运行一些包含数百万个十进制表示的数据点的100k+模拟。我选择十进制而不是浮点数来获得浮点精度并易于对逻辑进行单元测试(因为使用浮点数时
0.1 + 0.1 + 0.1
不等于0.3...)。我希望能够通过使用PyPy加速模拟。但在测试过程中,我发现PyPy不能很好地处理 decimal.Decimal
或者 _pydecimal.Decimal
,而且速度明显比使用C语言实现decimal.Decimal
算术运算的CPython解释器慢。所以我复制/粘贴了整个代码库,并将所有Decimal
替换为float
,这样使用PyPy比CPython快了60-70倍,牺牲了精度。是否有任何解决方案可以在PyPy中同时具有Decimals精度和性能优势?我“可以”维护两个代码库:float
用于批量运行100k个模拟,Decimal
用于稍后检查有趣的结果 - 但这需要维护两个代码库... 这里有一些我在Raspberry Pi 4(Ubuntu Server 20.10,4 x 1.5GHZ ARM Cortex-A72,8GB RAM)
上进行验证的简单测试:import time
from decimal import Decimal
start = time.time()
val = Decimal('1.0')
mul = Decimal('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"decimal.Decimal: {val:.8f} in {round(end-start,4)} sec")
test_pydecimal.py
import time
from _pydecimal import Decimal
start = time.time()
val = Decimal('1.0')
mul = Decimal('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"pydecimal.Decimal: {val:.8f} in {round(end-start,4)} sec")
test_float.py
import time
from decimal import Decimal
start = time.time()
val = float('1.0')
mul = float('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"float: {val:.8f} in {round(end-start,4)} sec")
结果
测试 | Python 3.8.6 (GCC 10.2.0) | Python 3.6.9 -PyPy 7.3.1 with GCC 10.2.0 |
---|---|---|
test_decimal | 5.1131 秒 | 55.0829 秒 |
test_pydecimal | 315.4012 秒 | 40.1771 秒 |
test_float | 2.5607 秒 | 0.1273 秒 |
编辑 #1:
- 更新了示例(使用预计算乘数,在
print
之外测量时间)和结果表格:PyPy 和 CPython 在 Decimals 上的性能总体比较结果保持不变。 - 模拟主要由基本的算术操作(加、减、乘、除)组成,作用于随着时间变化的时间序列数据。
print()
可能会影响你的结果。我敢打赌将decimal.Decimal
转换为str
比转换为float
需要更多的努力。尝试在没有print()
的情况下进行时间实验。重要的是要理解,你也在计时print()
,这不是正确计时数据操作的方法,除非你真的想计时print()
。计时print()
不可靠的原因之一是由于缓冲。 - Michael Ruthfloat('1.000001')
,在 Python 中val
的值不变,但执行速度提高了 4 倍,在 PyPy 中则提高了 63 倍。顺便问一下,您需要什么精度级别和进行什么样的操作? - Jérôme Richardval
的示例,并更新了结果表并添加了有关计算的信息。精度为8
就足够了。 - user10370644