在Cython中进行双打加法时的精度损失

2024-10-01 22:29:44 发布

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

我目前正在尝试使用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)

有什么建议吗


Tags: 函数代码infornp精度rangecython
1条回答
网友
1楼 · 发布于 2024-10-01 22:29:44

首先,Python对于整数数学只有任意精度。对于浮点数学,Python浮点是IEEE双精度(64位)值,就像Cython双精度一样

假设您使用的是x86(或x86-64)平台,那么可能有几个罪魁祸首。x86体系结构为浮点数学提供了两种不同的指令集。经典路径使用x87指令集,所有计算实际上都以80位(又称“长双精度”)精度完成。当一个值(中间值或最终值)存储到内存中时,它将被截断为64位精度。只要它保留在FPU寄存器中,它就可以保持完整的80位精度

另一个可用的指令集使用所谓的SSE(数据流单指令多数据扩展指令集),它可以同时对多个操作数进行操作。但是,这些计算仅以该类型的“严格”精度(本例中为64位)完成

我猜Python选择了一条代码路径,而Cython选择了另一条。同样可能的是,它们都选择相同的指令集(最有可能是SSE指令集),但它们以不同的顺序添加中间产品。由于精度有限,求和的顺序会影响结果的准确性

另外,请注意,在这两种情况下,计算将至少以64位精度完成。没有你所说的“只有3位小数”的计算。请记住,一如既往,计算是用二进制浮点完成的,而不是十进制。这些值之间的真正差异可能只有几个低阶位

相关问题 更多 >

    热门问题