c - 初学者 C 难题 : why doesn't 25 == 25?

标签 c arrays gcc codelite

在我的中级 C 编程类(class)中,我的第一个实验室有一个简单的任务。我从用户那里获取了 8 个 double 组,然后是 1 个额外的 double 组。然后,我检查数组中一个 double 的平方加上数组中其他 double 的平方,看看它们是否等于给程序的最后一个输入(附加 double )的平方。

我的问题是,出于某种原因,当我的两个输入的平方等于附加输入的平方时,我的编译器并不这么认为。

请让我知道我在这里做错了什么;我将 Codelite 与 gnu gdb 调试器和 gcc 编译器一起使用。

示例输入:4 3 3 3 3 3 3 3 5

#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
    int input[8];
    double inputSquared[8];
int pairs[16];
int i, j, k;  //i and j are for loop workers.
double x;
int numPairs = 0;
printf("Welcome to Lab 1.\nEnter 8 integers.  After each entry, press the enter button.\n");
printf("---------------------------------------\n");
for(i=0; i<8; i++){
    printf("Enter integer %d:", i+1);
    scanf("%d", &input[i]);
    printf("\n");
}

//printf("Now enter one more integer.\n  The sum of the squares of the following o this integer squared.\n");
printf("Enter an integer: ");
scanf("%lf", &x);

for(k = 0; k<8; k++){
    inputSquared[k] = pow((double)input[k], 2);
}

for(i = 0; i<8; i++){
    for(j = i + 1; j<8-1; j++){  //does not check for pairs reflexively. If 1 is in the array, it does not check 1^2 + 1^2.
        printf("%lf, %lf; %lf; %lf, %d \n", inputSquared[i], inputSquared[j], pow(x, 2.0), inputSquared[i] + inputSquared[j], ((inputSquared[i] + inputSquared[j]) == ((pow(x, 2.0)))));
        if(inputSquared[i] + inputSquared[j] == pow(x, 2.0)){
            pairs[2 * numPairs] = input[i];
            pairs[2 * numPairs + 1] = input[j];
            numPairs++;
        }
    }
}
if(numPairs == 1)
    printf("\nYou have %d pair:", numPairs);  // grammar condition for having 1 pair
else
    printf("\nYou have %d pairs:\n", numPairs);

for(i = 0; i < numPairs; i++)
    printf("(%d,%d)", pairs[2 * i], pairs[2 * i + 1]);

scanf("%lf", &x);

return 0;
}

最佳答案

如果您将 x 的平方计算为:

x * x

甚至

(double)x * (double)x

然后你会得到一个精确的正方形。换句话说,

4 * 4 + 3 * 3 == 5 * 5             => 1 (true)
4.0 * 4.0 + 3.0 * 3.0 == 5.0 * 5.0 => 1 (true)

事实上,

5 * 5 == 5.0 * 5.0                 => 1 (true)

但是,

5 * 5 == pow(5.0, 2.0)             => 0 (false)

因为数学库(不是 编译器)不会检查 pow 的第二个参数是否存在恰好是一个小整数。它只是继续并通过计算 pow(x, p) = ⅇ<sup>p*ln(x)</sup> 计算出值.不幸的是,一般来说,该值不能表示为 double ——事实上,它通常甚至不是有理数,所以它根本没有真正的有限表示——数学库选择了一个合理的由泰勒级数(或类似的东西)计算的近似值。

所以不仅是pow(5.0, 2.0)稍微不准确,计算起来也相当复杂。鉴于 5 * 5只是一条机器指令。您或许可以得出自己的结论。


许多人会告诉您,您“永远不要”比较浮点值是否相等。该建议往往会导致(或来自)一种心理模型,在该模型中, float 是一种模糊的、失焦的东西,它可能会不可预测地波动,几乎就像它受到海森堡不确定性的影响一样。这实际上不是思考 float 的好方法。每个 float 都是某个有理数的精确表示;事实上,它是一个有理数的精确表示,其分母是 2 的幂,分子是 0 或 1 和 2k-1 之间的整数,对于一些较小的 k(52 对于 double 大多数现代 CPU)。

因此,在什么情况下浮点运算是精确的是完全可以预测的。例如,如果 x已知是一个整数,其绝对值小于一年中的秒数,则(double)x * x是完全正确的。另一方面,分母(当减少到最低项时)为奇数(或具有奇数因子)的分数永远不能精确表示为 float 。

关于c - 初学者 C 难题 : why doesn't 25 == 25?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18907036/

相关文章:

android - 如何在 Android NDK Revision 11 中切换 gcc 和 clang?

c - 链表使用push函数添加节点

java - 字符串数组不起作用。编译器不交互

php - 将 JSON 数组转换为 php 中的插入查询字符串

c++ - 标准 C++ assert() 如何工作以及如何重新定义它?

c - 为什么 gcc 给出警告 : implicit declaration of function qsort_r?

c - 运行代码恰好一秒钟

C:如何将 float 包裹到区间 [-pi, pi)

c - 这是使用 -falign-loops 选项时的 GCC 错误吗?

javascript - 从 Javascript 数组中删除相似的字符串