我想使用数百万个数据点(以小数表示)运行 100k+ 次模拟。我选择小数而不是浮点数是为了浮点精度和易于对我的逻辑进行单元测试(因为0.1 + 0.1 + 0.1
对于浮点数不等于 0.3...)。
我希望通过使用 PyPy 来加快模拟速度。但在我的测试过程中我遇到 PyPy 不处理decimal.Decimal
甚至_pydecimal.Decimal
一点也不差——而且比 CPython 解释器(使用 C 语言)慢得多decimal.Decimal
算术)。所以我复制/粘贴了我的整个代码库并替换了所有Decimal
s with float
并且性能提升巨大:PyPy 比 CPython 快 60-x70 倍 - 但牺牲了准确性。
是否有任何解决方案可以在 PyPy 中使用小数精度并具有性能优势?我“可以”维护两个代码库:float
对于批量运行 100k 次模拟,Decimal
用于稍后检查有趣的结果 - 但这需要维护两个代码库的开销......
这是我在上面运行的一些简单测试Raspberry Pi 4 (Ubuntu Server 20.10, 4 x 1.5GHZ ARM Cortex-A72, 8GB RAM)
用于复制:
test_decimal.py
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")
Results
Test |
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 sec |
55.0829 sec |
test_pydecimal |
315.4012 sec |
40.1771 sec |
test_float |
2.5607 sec |
0.1273 sec |
Edit #1:
- 更新了示例(使用预先计算的乘法器,测量时间之外
print
)和结果表:PyPy 和 CPython 在小数上的总体比较保持不变。
- 模拟主要由对具有变化值的时间序列数据进行基本数学运算(加、减、乘、除)组成。