GCC C++ pow accuracy - c++

So i was in a computing contest and i noticed a weird bug. pow(26,2) would always return 675, and sometimes 674? even though correct answer is 676. These sort of errors also occur with pow(26,3), pow(26,4) etc
After some debugging after the contest i believe the answer has to do with the fact int rounds down. Interestingly this kind of error has never occured to me before. The computer i had was running mingw on windows 8. GCC version was fairly new, like 2-3 months old i believe. But what i found was that if i turned the o1/o2/o3 optimization flag on these sort of error would miraculously disappear. pow(26,2) would always get 676 aka correct answer Can anyone explain why?
#include <cmath>
#include <iostream>
using namespace std;
int main() {
cout<<pow(26,2)<<endl;
cout<<int(pow(26,2))<<endl;
}
Results with doubles are weird.
double a=26;
double b=2;
cout<<int(pow(a,b))<<endl; #outputs 675
cout<<int(pow(26.0,2.0))<<endl; # outputs 676
cout<<int(pow(26*1.00,2*1.00))<<endl; # outputs 676

The function pow operates on two floating-point values, and can raise one to the other. This is done through approximating algorithm, as it is required to be able to handle values from the smallest to the largest.
As this is an approximating algorithm, it sometimes gets the value a little bit wrong. In most cases, this is OK. However, if you are interested in getting an exact result, don't use it.
I would strongly advice against using it for integers. And if the second operand is known (2, in this case) it is trivial to replace this with code that does this much faster and that return the correct value. For example:
template<typename T>
T square(T x)
{
return x * x;
}
To answer the actual question: Some compilers can replace calls to pow with other code, or eliminate it all together, when one or both arguments are known. This explains why you get different results.

Related

Result is one off in VS Studio Code but not on an online IDE [duplicate]

So i was in a computing contest and i noticed a weird bug. pow(26,2) would always return 675, and sometimes 674? even though correct answer is 676. These sort of errors also occur with pow(26,3), pow(26,4) etc
After some debugging after the contest i believe the answer has to do with the fact int rounds down. Interestingly this kind of error has never occured to me before. The computer i had was running mingw on windows 8. GCC version was fairly new, like 2-3 months old i believe. But what i found was that if i turned the o1/o2/o3 optimization flag on these sort of error would miraculously disappear. pow(26,2) would always get 676 aka correct answer Can anyone explain why?
#include <cmath>
#include <iostream>
using namespace std;
int main() {
cout<<pow(26,2)<<endl;
cout<<int(pow(26,2))<<endl;
}
Results with doubles are weird.
double a=26;
double b=2;
cout<<int(pow(a,b))<<endl; #outputs 675
cout<<int(pow(26.0,2.0))<<endl; # outputs 676
cout<<int(pow(26*1.00,2*1.00))<<endl; # outputs 676
The function pow operates on two floating-point values, and can raise one to the other. This is done through approximating algorithm, as it is required to be able to handle values from the smallest to the largest.
As this is an approximating algorithm, it sometimes gets the value a little bit wrong. In most cases, this is OK. However, if you are interested in getting an exact result, don't use it.
I would strongly advice against using it for integers. And if the second operand is known (2, in this case) it is trivial to replace this with code that does this much faster and that return the correct value. For example:
template<typename T>
T square(T x)
{
return x * x;
}
To answer the actual question: Some compilers can replace calls to pow with other code, or eliminate it all together, when one or both arguments are known. This explains why you get different results.

Why is std::remquo so slow?

In some inner loop I have:
double x;
...
int i = x/h_;
double xx = x - i*h_;
Thinking that might be a better way to do this, I tried with std::remquo
double x;
...
int i;
double xx = std::remquo(x, h_, &i);
Suddenly, timings went from 2.6 seconds to 40 seconds (for many executions of the loop).
The timing test is difficult to replicate here, but I did a online code to see if someone can help me to understand what is going on.
naive version: https://godbolt.org/z/PnsfR8
remquo version: https://godbolt.org/z/NSMwyW
It looks like the main difference is that remquo is not inlined and the naive code is. If that is the case, what is the purpose of remquo if it is going to be always slower than the manual code? Is it a matter of accuracy (e.g. for large argument) or not relying on (not well defined) casting conversion?
I just realized that the remquo version is not even doing something equivalent to the first code. So I am using it wrong. In any case, I am surprised that remquo is so slow.
It's a rubbish function that was added to C99 to entice Fortran coders to switch to C. There's little reason to actually use it, so library vendors avoid wasting time optimizing it.
See also: What does the function remquo do and what can it be used for?.
BTW if you assumed that i gets the quotient stored in it, read the documentation more closely! (Or read the answers on the question linked in the previous paragraph).

What's wrong with my algorithm?

I was resolving some online mathematics tests, and thought it's too hard to find the solutions and put it in a program on devc++, I should have
153,370,371,407,
but there was missing a solution 407.
Here is the question: The number 153 has an interesting property. In other words, it is equal to the sum of the cubes of its digits:
13 + 53 + 33 = 153
370 is another number with the same property. There are two other three-digit natural numbers with three different digits, both smaller than 500, that have the same property. Find them.
And here is my program
#include<iostream.h>
#include<math.h>
using namespace std;
int main() {
int i,nr,a,b,c;
for(i=100;i<=500;i++) {
nr=i;
c=i%10;
b=i/10%10;
a=i/10/10;
if((pow(a,3)+pow(b,3)+pow(c,3))==nr) cout<<nr<<endl;
}
system("pause");
}
Perhaps pows return double leading to floating point inaccuracy.
Instead, try
if(a*a*a + b*b*b + c*c*c == nr)
cout ....
( [EDIT] Resolved since. Mostly guessing the question from the partial code, since the question is terribly formatted at this point, and is not editable either for some reason. )
Floating point calculations are not always exact, and comparing floating point values for equality is generally ill advised.
To the point, replace
if((pow(a,3)+pow(b,3)+pow(c,3))==nr)
with
if((a*a*a + b*b*b + c*c*c) == nr)
When I run that program I get those 4 answers.
pow is never supposed to be imprecise enough to have any rounding in this trivial test.
But there seems to be a tend in questions on SO that both pull c headers into C++ and use system("pause"); that a version of pow is being used that is seriously less accurate than it ought to be. So the earlier two answers (suggesting a way to not use pow) may be effectively correct. But only because something is wrong with you math library, not because a valid copy of pow gets that bad.
So you could find a better C++ environment or better math headers, or you could start some seriously defensive programming around the flaws in your copy of pow
But if that doesn't fix it, the next thing to suspect would be endl isn't working quite correctly before that pause. Maybe you are seeing some output buffering problem. Anyway, I'm pretty sure the code is fine (even its use of pow) and the problem is in the math or I/O library functions.

beginner c++ textbook disagrees with actual output I get when compiling math equations

Hi so the following are questions from my hw this week, I answered them in accordance with the material I found in my textbook but because we are graded extremely harsh in this class I thought I'd run them through a compiler to see if my answers were right. However when I run them in a c++ compiler I can't get the pow, ceil, or floor functions to return a floating point, they only return integers which disagrees with what my book says they should return??? I showed what my answers to the hw should be according to the book, and in parentheses what happens when i compile them.
question; what my book
says the
answer
should be; (what the compiler shows);
A) pow(2,3); 8.0; (my book says pow only returns a floating
point but this only returns an integer,
even when I change the function to be
pow(2.0,3.0) I only get 8);
B) fabs(-3.5); 3.5; (this one works, it returns 3.5);
C) sqrt(pow(3,2)); 2.8; (returns 2.82843, how am I supposed to
know how many decimals to put out?);
D) 7 / abs(-2); 3; (this one works);
E) ceil(5.8); 6.0; (only returns the integer 6);
F) floor(5.8); 5.0; (only returns the integer 5);
From what you have described, everything is working as expected. You haven't included the code you've written so this is somewhat of a guess - but you are asking the computer to print out the value of some numbers. You are getting 8 but you are expecting 8.0. Neither you nor the computer are wrong. You just need to ask the computer to print out decimal point values, even if the number you're asking to print is exactly an integer.
Question; what my book says the answer should be; (what the compiler shows);
The compiler doesn't show anything about types. (Well, it can, but you have to poke deep. For example, make it generate assembly, or use a trick that shows the type as a compiler error.)
Presumably you are basing your thoughts on what you see printed. For example, consider this C++11 program:
#include <cmath>
#include <iostream>
int main () {
auto pow_2_3 = std::pow(2,3);
// int eight {pow_2_3}; // Compilation error.
std::cout << pow_2_3 << '\n';
}
This prints "8" (not 8.0). Does that mean the type is an integer? Of course not. That "8" just means the default formatting is stripping the trailing zeros, and the decimal point as well.
You'll get a compilation error if you uncomment the commented-out line because a double cannot be narrowed to an integer. Not even if it's exact, and not even if it's known at compile time. The type of pow_2_3 is a double, just as the standard specifies. If std::pow(2,3) actually is an integer on your computer with your compiler, then you have a non-compliant compiler.
The same is true for std::ceil and std::floor. They return doubles, not integers.

strange results with /fp:fast

We have some code that looks like this:
inline int calc_something(double x) {
if (x > 0.0) {
// do something
return 1;
} else {
// do something else
return 0;
}
}
Unfortunately, when using the flag /fp:fast, we get calc_something(0)==1 so we are clearly taking the wrong code path. This only happens when we use the method at multiple points in our code with different parameters, so I think there is some fishy optimization going on here from the compiler (Microsoft Visual Studio 2008, SP1).
Also, the above problem goes away when we change the interface to
inline int calc_something(const double& x) {
But I have no idea why this fixes the strange behaviour. Can anyone explane this behaviour? If I cannot understand what's going on we will have to remove the /fp:fastswitch, but this would make our application quite a bit slower.
I'm not familiar enough with FPUs to comment with any certainty, but my guess would be that the compiler is letting an existing value that it thinks should be equal to x sit in on that comparison. Maybe you go y = x + 20.; y = y - 20; y is already on the FP stack, so rather than load x the compiler just compares against y. But due to rounding errors, y isn't quite 0.0 like it is supposed to be, and you get the odd results you see.
For a better explanation: Why is cos(x) != cos(y) even though x == y? from the C++FAQ lite. This is part of what I'm trying to get across, I just couldn't remember where exactly I had read it until just now.
Changing to a const reference fixes this because the compiler is worried about aliasing. It forces a load from x because it can't assume its value hasn't changed at some point after creating y, and since x is actually exactly 0.0 [which is representable in every floating point format I'm familiar with] the rounding errors vanish.
I'm pretty sure MS provides a pragma that allows you to set the FP flags on a per-function basis. Or you could move this routine to a separate file and give that file custom flags. Either way, it could prevent your whole program from suffering just to keep that one routine happy.
what are the results of calc_something(0L), or calc_something(0.0f) ? It could be linked to the size of the types before casting. An integer is 4 bytes, a double is 8.
Have you tried looking at the asembled code, to see how the aforementioned conversion is done ?
Googling for 'fp fast', I found this post [social.msdn.microsoft.com]
As I've said in other question, compilers suck at generating floating point code. The article Dennis links to explains the problems well. Here's another: An MSDN article.
If the performance of the code is important, you can easily1 out-perform the compiler by writing your own assembler code. If your algoritm is vectorisable then you can make use of SIMD too (with a slight loss of precision though).
Assuming you understand the way the FPU works.
inline int calc_something(double x) will (probably) use an 80 bits register. inline int calc_something(const double& x) would store the double in memory, where it takes 64 bits. That at least explains the difference between the two.
However, I find your test quite fishy to begin with. The results of calc_something are extremely sensitive to rounding of its input. Your FP algorithms should be robust to rounding. calc_something(1.0-(1.0/3.0)*3) should be the same as calc_something(0.0).
I think the behavior is correct.
You never compare a floating point number up to less than the holding type's precision.
Something that comes from zero may be equal, greater or less than another zero.
See http://floating-point-gui.de/