Possible Duplicate:
C compiler bug (floating point arithmetic)?
I've got two doubles which I can guarantee are exactly equal to 150 decimal places - ie. the following code:
printf("***current line time is %5.150lf\n", current_line->time);
printf("***time for comparison is %5.150lf\n", (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS));
...returns:
***current line time is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
***time for comparison is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
FIVE_MINUTES_IN_DAYS
is #defined, and current_line->time
and last_stage_four_print_time
are both doubles.
My problem is that the next line of my debugging code:
printf("if condition is %d\n", (current_line->time >= (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)));
returns the following:
if condition is 0
Can anyone tell me what's going on here? I am aware of the non-decimal/inexact nature of floats
and doubles
but these are not subject to any error at all (the original figures have all been read with sscanf
or #defined and are all specified to 10 decimal places).
EDIT: My mistake was assuming that printf
-ing the doubles accurately represented them in memory, which was wrong because one value is being calculated on-the-fly. Declaring (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)
as threshold_time
and using that instead fixed the problem. I will make sure to use an epsilon for my comparisons - I knew that was the way to go, I was just confused as to why these values which I (incorrectly) thought looked the same were apparently inequal.
#define FIVE_MINUTES_IN_DAYS 0.0034722222
Matt Lyons 2012-04-04 07:03
a+b
into a float. Use a unsigned char pointer and cast the address of the float into it and check whether the bit patterns of the two floats really match. If they do, then there's something fishy. Else the answers given here are the ways to g - Pavan Manjunath 2012-04-04 07:08
%a
format. Finally, since it hasn't been mentioned, a reason calculated and stored doubles can differ on intel architecture is 80-bit registers being used for the calculations before results are stored to 64-bit doubles in memory - Brian Swift 2012-04-04 09:35
Floats certainly are not accurate to 150 significant digits, so I 'm not sure what conclusion can be drawn from the "visual" comparison (if any).
On the other hand, the values are obviously not bit-identical (and how could they be, since one of them is calculated on the spot with addition?). So it's not really clear why the behavior you see is unexpected.
Don't ever compare floats like that, just do the standard comparison of difference vs epsilon.
threshold_value
as (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)
fixed the problem - Matt Lyons 2012-04-04 07:06
Read about floating point representation (particularly http://en.wikipedia.org/wiki/IEEE_754-2008). Try printing the actual contents of the bytes containing the doubles as hexadecimal and they won't match bit for bit. The proper comparison for floats is in Knuth (Seminumerical algorithms). Simply (replace bool with int and float with double, true with 1):
bool almostEqual(float x, float y, float epsilon)
{
if (x == 0.0 && y == 0.0) {
return true;
}
if (fabs(x) > fabs(y)) {
return fabs((x - y) / x) < epsilon;
} else {
return fabs((x - y) / y) < epsilon;
}
}
You should always use an EPSILON value for comparison of floats and doubles to check for equality. Even though it looks the same the internal representation is not guaranteed to match because of the way these types of numbers are represented in binary.
You can do something like
#define EPSILON 0.00001
...
if (fabs(a - b) <= EPSILON) return 1; // they are equal
return 0;
Jesus is right about how to solve this.
As for why... in one case you read in a constant value, in the other case you perform an addition operation. Even if the printed output is exactly the same, the binary representation can be slightly different.
Try inspecting the memory backing the two double's and see if any bits are different (there will be differences).
For a comprehensive treatment, I recommend
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
As for why... in one case you read in a constant value, in the other case you perform an addition operation.
- nailed it, see the edit : - Matt Lyons 2012-04-04 07:15
In general you shouldn't use == to compare floats or doubles. You should instead check that the difference is smaller than some small number.
double second_number = last_stage_four_print_time + FIVE_MINUTES_IN_DAYS;
if (fabs(current_line->time - second_number) < 0.001 || current_line->time > second_number){
// your comparison code
}
First, doubles have just 15-16 decimal places (log_2 of 52 bit matissa).
Second, if you want to compare, use the already mentioned epsilon.
Thirdly, for debugging, print the hex value.
#define
forFIVE_MINUTES_IN_DAYS
? Is it along double
? There's a lot you're not showing us - Potatoswatter 2012-04-04 07:01