3

请让我知道以下 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;
}

请参阅我对代码更改的评论。该函数为某些输入提供不同的值。由于结合了这两个语句,浮点数是否会出错?

4

2 回答 2

4

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

您可能会遇到四舍五入错误,因为初始结果 (new_re) 已四舍五入,然后添加到 c_re 。

正如尼克拉斯所说:

以更高的精度存储中间值

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

于 2012-10-11T05:42:48.973 回答
1

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

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

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

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

于 2012-10-11T05:57:09.967 回答