Click here to Skip to main content
15,900,589 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
See more:
I am comparing two variables a and b of type double, is all scenarios the while statement is true and working fine and in a specific scenario, the while statement fails and becomes an infinite loop.

These are the scenarios along with values of a and b

Scenario that works:
a : 12966389161.426863
b : 12966389161.735195
(or)
a : 12966389167.426863
b : 12966389496.760206
while(a < b)
{
    //fetch next filetime;
    a = FILETIME.GetTotalSeconds();
}

Scenario thats not working: while loop fails
a : 12966127670.187000
b : 12966127670.788626

for these values, a < b check is returning false.

What could be the reason, how should i solve it?

Further info about the rest of the code:

class TrendPoint
{
public:
CTime	m_Time;
float	m_Value;
}

class CTime : public FILETIME
{
public:
CTime(FILETIME time)	{*this = time;}
public:
double          GetTotalSeconds()
                         {return static_cast<unsigned __int64>(*this)/1e7;}//converting 64bit to 32 bit
}


Scenario:
float duration = 0.601626; //this is also a runtime value, that generated but its a float of value less than 1
double a = trendpoint.m_Time.GetTotalSeconds();
double b = trendpoint.m_Time.GetTotalSeconds() + duration;
while(a < b)
{
//fetch next trendpoint;
a = trendpoint.m_Time.GetTotalSeconds();
}
This is failing for 'a' as 12966127670.187000 and 'b' as 12966127670.788626 as explained at the start.
Posted
Updated 22-Nov-11 11:11am
v4
Comments
CPallini 22-Nov-11 15:20pm    
Why shouldn't it consider the condition false? as far as I can see 12966127670.788626 is not less than 12966127670.187000.
Sergey Alexandrovich Kryukov 22-Nov-11 16:30pm    
A simple problem, please see my answer.
--SA
amarasat 22-Nov-11 15:28pm    
sorry, i have mistyped a and b, now i updated the question.
JackDingler 22-Nov-11 15:34pm    
Those values should compare without problems.What is FILETIME?

What are the data types for a and b? Are they a custom class with an overloaded '<' operator?
Sergey Alexandrovich Kryukov 22-Nov-11 16:30pm    
FILETIME is a Windows structure and is irrelevant here. The solution is really simple, please see my answer.
--SA

I have just tested by forcing the values as
C++
a = 12966127670.187000;
b = 12966127670.788626;

and it correctly tests a is less than b, so I must presume that the information you have given above is incorrect somewhere.
 
Share this answer
 
Comments
Albert Holguin 23-Nov-11 7:16am    
Crossed my mind to do this but I was a bit busy last night... +5
Are you a software developer or not? You should have indicated the type of a and b, because this is critically important. If the type is single, a == b, so you need to use the type double. The type single is not used often because of its precision insufficient for most problems, prefer using double.

Do you understand that it is not possible to create a type to represent any real number as it is understood in mathematics, because a real number may require infinite amount of memory?

—SA
 
Share this answer
 
Comments
amarasat 22-Nov-11 16:53pm    
I have already stated that it is of type double, ofcourse i am a software developer, thats y i have specified that those variables are of type double twice in the whole question, and the values are the runtime values at which it is failing.
Albert Holguin 22-Nov-11 16:57pm    
He does indicate type double... and as far as I can see, that wasn't changed since the original posting.
amarasat 22-Nov-11 17:09pm    
updated the question with extra code and info, thanks a lot.
It might also depend on your floating point options... as there are options to select between faster computation or more precise one (IEEE).

That being said, I have made a small test program

C++
int i = 0;
float f = 0.601626;
double a = 1.0;
double b = a + f;

while (a < b)
{
    a *= 1.1;
    b = a + f;
    ++i;
}


That program fails after 386 iterations. At that point a is equal to 9 496 782 049 180 368.0 Thus it actually fails somewhere between 8.6e15 and 9.5e15 when adding 0.601626 to a double.

By the way 2^53 is equal to 9.001e15 (and it would probably fail at that point... Also a lot of imprecision would have been added if the additions are cumulatives).

Thus, I don't understand why the program does not works as expected as the OP numbers are around a million time smaller than that...

Also, how do you actuall print that number 12966127670.788626 as it has more than 15 significant digits so that number... Last 2 digits are probably incorrect. Are those values printed or inspected from code or the second value is what you think it should be.

By the way, are you always adding 0.601626 and in particular when it fails? And are you computation as simple as a simple addition. If they are somehow more complex (and you have inspected b, then there might some rounding errors you havent noticed).

Finally be aware that values printed are rounded so there can be a difference in the actual float value and what is displayed if you display 15 or more digits.

*** In you case, you might consider using 64 bits integers everywhere to avoid loosing some precision ***.
 
Share this answer
 
v2
Comments
Stefan_Lang 23-Nov-11 4:22am    
See my solution: a+f is, in fact, a float value!
P.S.: or not, as I just found :-(
Philippe Mori 23-Nov-11 8:44am    
I think, I finally found another part of the problem.

He is divising a 64 bit by 1e7. Assuming that the 64 bits number is unsigned, then it can represent 2^64/1e7 seconds. This give 1.844672e12 seconds. It is still above problematic numbers of the OP...

By the way the 64 bit numbers is first converted to a double. Thus it already loose up to 11 bits of precision there. Thus at that point the precision is in the order of 0.2 ms.

At first, it should still be safe... if the computation are as simple as we guess.

Anyway, the OP does not give us enough information to really pinpoint the problem and he does give some misleading information as for example a double cannot have more than 15 significant digits so the digits he gaves are not the real a and b.

In fact, he should give us the original 64 bits values and all computations leading to a and b.
Binary arithmetic operators with mixed operand types convert the result to a common base type. See http://osr507doc.sco.com/en/tools/clang_conv_implicit.html#clang_conv_impl_arithmetic[^]
So your calculation of b will be temporarily converted to float, because duration is of type float:
C++
double b = trendpoint.m_Time.GetTotalSeconds() + duration;

is equivalent to
C++
double b = (double)((float)(trendpoint.m_Time.GetTotalSeconds()) + duration);

This means, if duration is very small compared to the first operand, it will just be cut off in this operation!

To solve this, explicitely cast your second operand to double, or, better yet, declare it type double right from the start.

P.S.: I just reread that article I linked to and apparently I misinterpreted it. Sorry, looks like this isn't itt after all.

Maybe you still should make duration type double, as I suggested, but I am no longer sure it would solve your problem.
 
Share this answer
 
v3
I don't see where the time ever gets updated. It looks like you initialize the time once, and then compare the same values forever without ever getting the current time again.

It looks like you need to add a function.

C++
while(a < b)
{
   //fetch next trendpoint;
    trendpoint.m_Time.GetCurrentTime();
    a = trendpoint.m_Time.GetTotalSeconds();
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900