C中的浮点运算出错

时间:2012-10-11 05:35:42

标签: c++ c floating-point floating-accuracy

请告诉我以下C函数之间的区别。

static int mandel(float c_re, float c_im, int count) {
    float z_re = c_re, z_im = c_im;
    int i;
    for (i = 0; i < count; ++i) {
        if (z_re * z_re + z_im * z_im > 4.f)
            break;

        float new_re = z_re*z_re - z_im*z_im;
        float new_im = 2.f * z_re * z_im;
        z_re = c_re + new_re;
        z_im = c_im + new_im;
    }

    return i;
}

以下

static int mandel(float c_re, float c_im, int count) {
    float z_re = c_re, z_im = c_im;
    int i;
    for (i = 0; i < count; ++i) {
        if (z_re * z_re + z_im * z_im > 4.f)
            break;

        float new_im = 2.f * z_re * z_im;
        z_re = c_re + z_re*z_re - z_im*z_im;//I have combined the statements here and removed float new_re
        z_im = c_im + new_im;
    }

    return i;
}

请参阅我对代码更改的注释。函数为某些输入提供不同的值。由于结合了这两个陈述,浮动是否会被误解?

2 个答案:

答案 0 :(得分:4)

在数学中,这两个陈述是等价的。但是在计算机硬件中它们可能不是。

你可能会出错,因为初始结果(new_re)被舍入,然后被添加到c_re。

正如尼克拉斯所说:

  

中间值以更高的精度存储

因此new_re的结果在存储到new_re时可能会丢失一些浮点数,但如果将中间值添加到c_re,则c_re的较小值与new_re计算的较低有效值相结合可能会导致最终结果。

答案 1 :(得分:1)

在评估数学表达式时,允许C或C ++编译器生成的代码以更高的精度保持中间结果。

例如,在x86计算机上,C和C ++ double值通常为64-bits IEEE754个浮点数,但数学处理器堆栈在进行计算时每个值使用80位。

这意味着计算的确切结果将取决于临时存储在内存中的位置以及将其保存在fp堆栈中的位置。通常这不是问题,因为临时值的精度比存储值的精度高......但这并不总是正确的,因为计算可能是围绕浮点预期的舍入规则设计的

另请注意,编译器提供特殊标志以要求对数学评估严格要求或允许它们非常自由地帮助优化(包括忽略将操作存储到局部变量或将操作重写为理论数学等效版本)。今天的默认值通常有点自由,而且不是很严格,因为这会损害性能。