问题
I was doing something in C++ (CodeBlocks), but I found a weird problem. I sent my code to my friend (he tested it in DevC++) and it worked. I tried these two codes:
#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; }
}
But, then I changed the main function like this (and it didn't work):
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; }
}
Anyone knows what's the problem ?
回答1:
Unless you tell us what was your "weird" error, I'm assuming that, your second snippet code prints:
Doesn't work
The problem is, you are comparing floating point numbers because pow()
returns floating points
, see the definition of pow() function.
Floating point math is not exact because of Rounding Errors. Simple values like 9.0 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment. For example:
float a = 9.0 + 16.0
float b = 25.0
if(a == b) // can be false!
if(a >= b) // can also be false!
Even
if( Math.abs(a-b) < 0.00001) // wrong - don't do this
This is a bad way to do it because a fixed epsilon
(0.00001) chosen because it “looks small” could actually be way too large when the numbers being compared are very small as well.
I personally use the following method,
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;
}
}
And don't forget to read What Every Computer Scientist Should Know About Floating-Point Arithmetic!
Reference: This is the reference of my answer.
Edit: As the OP's problem concerning about C++
, so here is the edited version of 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;
}
The output is :
Works
Compiler : Cygwin C++ Compiler.
Cygwin Version: 1.7.25
回答2:
It worked on ideone.com too ! 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; }
}
回答3:
Variable types.
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/
try
> 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;
> } }
The above doesn't work in VS 2013 either.
I got it to work by using a function
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);
}
}
This seems to indicate it is, like CoryKramer pointed out, a floating point rounding error. He's also right about the d suffix not being valid for double literals, so I changed the code to correct that as well.
回答4:
The problem is that the math.h doesn't work, so I have to use cmath. Second, not int, but float or double.
Code:
#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;
}
}
来源:https://stackoverflow.com/questions/30628945/codeblocks-c-bug