在我的中级 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/