代码块 C++ 错误

CodeBlocks C++ Bug

我正在用 C++ (CodeBlocks) 做一些事情,但我发现了一个奇怪的问题。我将我的代码发送给了我的朋友(他在 DevC++ 中对其进行了测试)并且成功了。 我试过这两个代码:

#include <iostream>
#include <math.h>
using namespace std;

int main() //this function works
{
    if (pow(3, 2) + pow(4, 2) == pow(5, 2)) {
        cout << "Works" << endl;
    } else { cout << "Nope" << endl; } 
}

但是,然后我像这样更改了主要功能(但它没有用):

int main() //this function doesn't work
{
    int t1 = 3, t2 = 4, t3 = 5;
    if (pow(t1, 2) + pow(t2, 2) == pow(t3, 2)) {
        cout << "Works" << endl;
    } else { cout << "Doesn't work" << endl; }
}

有人知道问题出在哪里吗?

变量类型。

double pow (double base     , double exponent);
     float pow (float base      , float exponent);
long double pow (long double base, long double exponent);
     double pow (Type1 base      , Type2 exponent);        // additional overloads

http://www.cplusplus.com/reference/cmath/pow/

尝试

> int main() {
>     double d1 = 3.0, d2 = 4.0, d3 = 5.0;
>     if(pow(d1,2) + pow(d2,2) == pow(d3,2)) {
>         cout << "Works" << endl;
>     }
>     else {
>         cout << "Nope" << endl;
>     } }

以上在 VS 2013 中也不起作用。

我使用一个函数让它工作

bool CheckPyth(double a, double b, double c) {
  double aa = pow(a,2);
  double bb = pow(b,2);
  double cc = pow(c,2);

  if(aa + bb == cc) {
    return(true);
  }
  else {
    return(false);
  }
}

这似乎表明,就像 CoryKramer 指出的那样,这是一个浮点舍入错误。他关于 d 后缀对双文字无效的说法也是正确的,所以我也更改了代码以更正它。

它也适用于 ideone.com! http://ideone.com/3XcY4G

    int main() 
{
    int t1 = 3, t2 = 4, t3 = 5;
    if (pow(t1, 2) + pow(t2, 2) == pow(t3, 2)) {
        cout << "Works" << endl;
    } else { cout << "Doesn't work" << endl; }
}

除非你告诉我们你的 "weird" 错误是什么,否则我假设你的第二个代码片段打印:

Doesn't work

问题是,您正在比较浮点数,因为 pow() returns floating points, see the definition of pow() function.

由于 Rounding Errors,浮点数计算不准确。像 9.0 这样的简单值不能用二进制浮点数来精确表示,而且浮点数的精度有限意味着运算顺序的微小变化都会改变结果。不同的编译器和 CPU 架构以不同的精度存储临时结果,因此结果会根据您的环境细节而有所不同。例如:

    float a = 9.0 + 16.0
    float b = 25.0
    if(a == b) // can be false!
    if(a >= b) // can also be false!

甚至

    if( Math.abs(a-b) < 0.00001) // wrong - don't do this

这是一个糟糕的方法,因为选择固定 epsilon (0.00001) 是因为它“看起来很小”,当被比较的数字也非常小时,它实际上可能太大了。

我个人用的是下面的方法,

public static boolean nearlyEqual(float a, float b, float epsilon) {
        final float absA = Math.abs(a);
        final float absB = Math.abs(b);
        final float diff = Math.abs(a - b);

        if (a == b) { // shortcut, handles infinities
            return true;
        } else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
            // a or b is zero or both are extremely close to it
            // relative error is less meaningful here
            return diff < (epsilon * Float.MIN_NORMAL);
        } else { // use relative error
            return diff / Math.min((absA + absB), Float.MAX_VALUE) < epsilon;
        }
    }

并且不要忘记阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

参考: This是我回答的参考

编辑: 由于 OP 的问题涉及 C++,因此这里是 nearlyEqual() 的编辑版本:

#include <iostream>     // std::cout
#include <cmath>        // std::abs
#include <algorithm>    // std::min
using namespace std;

#define MIN_NORMAL 1.17549435E-38f
#define MAX_VALUE 3.4028235E38f

bool nearlyEqual(float a, float b, float epsilon) {
    float absA = std::abs(a);
    float absB = std::abs(b);
    float diff = std::abs(a - b);

    if (a == b) {
        return true;
    } else if (a == 0 || b == 0 || diff < MIN_NORMAL) {
        return diff < (epsilon * MIN_NORMAL);
    } else {
        return diff / std::min(absA + absB, MAX_VALUE) < epsilon;
    }
}

int main(void) {
    float t1 = 3.0, t2 = 4.0, t3 = 5.0, epsilon = 0.0000000001; // don't use int here!
    if (nearlyEqual((pow(t1, 2) + pow(t2, 2)), pow(t3, 2), epsilon)) {
        cout << "Works" << endl;
    } else {
        cout << "Doesn't work" << endl;
    }
    return 0;
}

输出为:

Works

编译器: Cygwin C++ 编译器。

Cygwin 版本:1.7.25

问题是 math.h 不起作用,所以我必须使用 cmath。第二,不是int,而是float或double。

代码:

#include <iostream>
#include <cmath>

using namespace std;

int main()
{

    float t1 = 3, t2 = 4, t3 = 5;

    if (pow(t1, 2) + pow(t2, 2) == pow(t3, 2)) {
        cout << "PT" << endl;
    }
    else {
        cout << pow(t1, 2) + pow(t2, 2) << endl;
        cout << pow(t3, 2) << endl;
    }

}