I was testing a part of my code when I discovered something strange. I was testing (function AmawIn) if a variable a is within a range [b,c] and when a was equal to b or c the result could be false. Changing the types worked but not always. I changed the code testing different algorithms of AmawIn as you can read. I am using gcc 11.3 (the last adtools). For info, I have just compiled the code with gcc Debian 11.3 with the same output. After testing a lot, I have got no more ideas. I hope someone will help me. I compile with Quote:
if (animt > 0) {
anim += animV;
if (!AmawIn(anim, animSnew, animEnew ) ) { //[color=FF6600]HERE IS THE PROBLEM[/color]
cout <<"( in AmawIn: "<<anim<<" not in "<<animSnew<<":"<<animEnew<<")"<<endl;
Try "std::fixed << std::setprecision(8)" when printing those numbers. 8 or more, I don't remember how many digits were exactly required but it should show the issue with those floating point numbers.
To be serious though, you are incrementally adding 0.2 in decimal ie base 10, to a floating point number stored in binary ie base 2. But 2 / 10 cannot be exactly expressed as base 2 fraction (in the same way that 1/ 3 can't be exactly expressed in a base 10 fraction (ie 0.3333333...) so each time you accumulate a small rounding error, so the final value you compare is slightly more than 4.4 and so your program correctly reports that it's outside the range.
@yescop Thanks for taking time to read my source and answer.
Capehill, the precision is 16 (using double). Broadblues, I am not a looser but a too confident person. I was thinking wrongly that the comparison in gcc was smarter. For example, if a=1.0 and b=1.0, a==b would always return true. But it is not true because the comparison will examine all digits (here 16) and not only a few (here only one digit, smarter as the variables used in my code were equal to numbers from 1 to 4 with a step of 0.2) and as you wrote, the conversion is not precise.
Since a lot of months without an amiga to love, I was lost. Now I feel happiness again with a Sam Flex 800 .
float or double you would get the same kind of problem. Quote:
Broadblues, I am not a looser but a too confident person.
Of course not, I was just joking based on your question title
Quote:
I was thinking wrongly that the comparison in gcc was smarter. For example, if a=1.0 and b=1.0, a==b would always return true.
In fact it will, the problem was that after your progressive calculations a was 1.0 and b 0.9999999 or in your specific case perhaps 4.4 and 4.399999
Quote:
But it is not true because the comparison will examine all digits (here 16) and not only a few (here only one digit, smarter as the variables used in my code were equal to numbers from 1 to 4 with a step of 0.2) and as you wrote, the conversion is not precise.
It's an easy trap to fall into. If you had chosen 0.25 as the interval you might have found it worked at first until later when you changed the step to 0.2, so it's good in a way that you found it sooner rather than later.
I would convert your iterator to an integer, multipled by 10 so that you go in steps of 2 (instead of 0,2)
Then you can make an exact comparison in the range 0 to 44 and if you need the value as a float calculate it with a cast
Just to clarify, by precision I meant cout output's display precision (how many digits you see), instead of amount of bits in variables (float or double).
In math you learn about infinities, max and min number are infinities, another infinity is numbers between 1.0 to 2.0. to store an infinite number, you will need infinite space.
In a double some bits are used for exponent, another is fractions. 1/1, ½,1/4,1/8,1/16,1/32,1/64, When you run out of bits you lose the resolution / accuracy.
In the meantime, I wrote this code. May be for someone it is overkill but it works well. Your solution using int is a good idea but not suitable in my case.
Here is the code for all who wants to know and feel to use it freely. It is in C++
template <class T>
bool AmawIn(const T a, const T b,const T c) {
T bb=b,cc=c;
T eps = std::numeric_limits<T>::epsilon()*100;
if (b > c) { T tmp=bb; bb = cc; cc = tmp;}
if ( (a>bb) && (a<cc)) return true;
if ( (fabs(a-bb) < eps) || (fabs(cc-a) < eps) ) return true;
return false;
}
Capehill, I had understood your purpose and used this to display the numbers