我目前正在尝试使用Cython优化Python代码。我需要的输出是完全相同的,但我希望与精度的麻烦。据我所知,Python具有无限精度,Cython的“Double”相当于Python浮点。我正在努力使用下面的函数(不允许共享代码-这是一个具有类似结构的虚拟函数):
def dummyfunction(c_np.ndarray[double, ndim=1] dummyarray, int a, int b, const c_np.uint8_t[:,:] dummyimg):
cdef double q = 0.111
cdef double w = 0.222
cdef double e = 0.333
cdef double[:] dummyview = dummyarray
cdef int i, j
cdef int r, g, b
for i in range(a):
for j in range(b):
r = dummyimg[j][0]
g = dummyimg[j][1]
b = dummyimg[j][2]
dummyarray[i * b + j] = (
q * r
+ w * g
+ e * b
)
dummyarray[:] = dummyview #i'm updating a class attribute in place
我试过打印“qr”、“wg”和“e*b”。这些产品的精度与Python中的精度相同!问题在于将这三个值相加。它只留下小数点后三位。我觉得这是因为在大多数情况下,被求和的3个分量中的一个分量最多只有3个小数位(例如35.87999999995、51.0689999999996、9.348)。Python似乎将其归结为更高的精度(即96.29699999998 vs 96.297)
有什么建议吗
首先,Python对于整数数学只有任意精度。对于浮点数学,Python浮点是IEEE双精度(64位)值,就像Cython双精度一样
假设您使用的是x86(或x86-64)平台,那么可能有几个罪魁祸首。x86体系结构为浮点数学提供了两种不同的指令集。经典路径使用x87指令集,所有计算实际上都以80位(又称“长双精度”)精度完成。当一个值(中间值或最终值)存储到内存中时,它将被截断为64位精度。只要它保留在FPU寄存器中,它就可以保持完整的80位精度
另一个可用的指令集使用所谓的SSE(数据流单指令多数据扩展指令集),它可以同时对多个操作数进行操作。但是,这些计算仅以该类型的“严格”精度(本例中为64位)完成
我猜Python选择了一条代码路径,而Cython选择了另一条。同样可能的是,它们都选择相同的指令集(最有可能是SSE指令集),但它们以不同的顺序添加中间产品。由于精度有限,求和的顺序会影响结果的准确性
另外,请注意,在这两种情况下,计算将至少以64位精度完成。没有你所说的“只有3位小数”的计算。请记住,一如既往,计算是用二进制浮点完成的,而不是十进制。这些值之间的真正差异可能只有几个低阶位
相关问题 更多 >
编程相关推荐