Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
VladimirF
What was the point of this code? Ans how it differs from:
Code:
_tprintf(_T("%.2f"), fAmt);
The multiply and then divide by 1000 part ensures that he doesn't lose the 3-rd decimal place, i.e. 1237.8599999999999 becomes 1237.86 and 1237.8549999999999 becomes 1237.85.
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
VladimirF
... floats have significantly lower precision compared to doubles.
Forgot to comment on this one. Yes, indeed the type double has 15 digits of precision while an older type float has only 7. But is it really making a big difference in the OP's case?
You would normally use double over float when dealing with a very small or very large numbers, or when you need to know the difference between, say, the 6th or 7th decimal digit. This may not be that crucial when dealing with most world currencies. (Again, the company's policy has to come into play here.)
So if the OP's database and/or other storage is coded for the use of float I would not rush to change it over to double. As besides an obvious hassle of converting databases as well as the existing code to a new type (that in itself is fraught with danger) you're also getting a tradeoff of increasing the size of your variables in 2 (i.e. 4 bytes for float and 8 bytes for double). For a large database this can cause a visible increase in its overall size.
I should also point out that if I was to code a brand new application from scratch I'd probably choose type double over float just for the sake of compatibility with the future technology. But I wouldn't worry if the code is already written to use float's.
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
ahmd
The multiply and then divide by 1000 part ensures that he doesn't lose the 3-rd decimal place...
I don't understand that.
However, I've modified your rounding function to print input parameter (just to compare), and I still see no effect of your transformation:
Code:
void printAmountForAUser(double fAmt)
{
_tprintf(_T("%.2f\n"), fAmt);
//For a 3-digit precision
__int64 ulAmt = (__int64)(fAmt * 1000.0);
double fAmtRounded = (double)ulAmt / 1000.0;
_tprintf(_T("%.2f\n\n"), fAmtRounded);
}
int _tmain(int argc, _TCHAR* argv[])
{
printAmountForAUser(1237.8599999999999);
printAmountForAUser(1237.8549999999999);
return 0;
}
And result:
Quote:
1237.86
1237.86
1237.85
1237.85
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
VladimirF
However, I've modified your rounding function to print input parameter (just to compare), and I still see no effect of your transformation
Well, the CRT way of handling %.2f switch for the printf function might have been changed to do the rounding internally since I first wrote this method. If so, then multiplying and then dividing would not be necessary. I'd still stick with it thought, to make sure it works on other (possibly older) platforms.
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
ahmd
Well, the CRT way of handling %.2f switch for the printf function might have been changed to do the rounding internally since I first wrote this method.
Please forgive my persistence. I would really like to get it (if there is something here that I can’t understand). I hope that you would also like to get this right.
Forget printf. Let’s just look at the values in debugger. In this example:
Code:
void printAmountForAUser(double fAmt)
{
//For a 3-digit precision
__int64 ulAmt = (__int64)(fAmt * 1000.0);
double fAmtRounded = (double)ulAmt / 1000.0;
if(fAmt == fAmtRounded)
_tprintf(_T("EQ\n\n"));
}
I got EQ for 1237.8599999999999 (surprised?) and nothing for 1237.8549999999999.
I then noticed that your initial values didn’t quite make it into doubles.
I see for the first value
Code:
fAmt 1237.8599999999999 double
but for the second
Code:
fAmt 1237.8549999999998 double
First value multiplied by 1000 produced
Code:
ulAmt 1237860 __int64
Again, surprised?
But regardless, I am just trying to follow your logic with pen and paper. By multiplying/deviding your doubles you are effectively truncating them. There is NO ROUNDING! What am I missing? Are you using some obscure Intel Processor trick?
But my guess is that your code only appears to work, and only on that small data sample.
The behavior will also depend on the floating-point control flags (there was another thread about it today).
Re: Adding doubles together produces different results in Release vs. Debug mode.
:) Sure, it's a valid argument. And no, there's no Intel Processor magic either. You might be right though. I posted the code without giving it a second thought. My original idea was that multiplication and division will take care of the last digit rounding, but I see your point. So let's change it to this:
Code:
void printAmountForAUser(double fAmt)
{
//For a 3-digit precision
__int64 ulAmt = (__int64)(fAmt * 100.0 + 0.5);
double fAmtRounded = (double)ulAmt / 100.0;
_tprintf(_T("%.2f"), fAmtRounded);
}
On the side note.
As comparison goes, I hope OP realizes that he/she should not be checking floats for equality in a simple == statement. The best alternative would be to use a method like this:
Code:
enum AMOUNT_COMPARISON_RESULT{
ACR_AMOUNTS_EQUAL = 0,
ACR_AMOUNT1_GREATER_THAN_AMOUNT2 = 1,
ACR_AMOUNT1_LESS_THAN_AMOUNT2 = -1,
};
AMOUNT_COMPARISON_RESULT compareTwoAmounts(double fAmt1, double fAmt2)
{
__int64 ulAmt1 = (__int64)(fAmt1 * 100.0 + 0.5); //Unbiased rounding of the 3rd decimal digit
__int64 ulAmt2 = (__int64)(fAmt2 * 100.0 + 0.5); //Unbiased rounding of the 3rd decimal digit
if(ulAmt1 > ulAmt2)
return ACR_AMOUNT1_GREATER_THAN_AMOUNT2;
else if(ulAmt1 < ulAmt2)
return ACR_AMOUNT1_LESS_THAN_AMOUNT2;
return ACR_AMOUNTS_EQUAL;
}
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
ahmd
On the side note.
As comparison goes, I hope OP realizes that he/she should not be checking floats for equality in a simple == statement.
Oh, I agree. I used == specifically to see if the bits match exactly (and they did for the first test case).
Re: Adding doubles together produces different results in Release vs. Debug mode.
Quote:
Originally Posted by
gageller
I did the rounding after adding up the individual parts
You should do the rounding on each value as you add them, not once at the end.
Consider adding the following 3 values;
$1.00499999
$2.00499999
$3.00499999
Assuming you want to round and display them to 2 decimal places, and show the total, rounding at the end will give you;
$1.00
+$2.00
+$3.00
= $6.01
($1.00499999 + $2.00499999 + $3.00499999 = 6.01499988)
If you round as you add each line, the result would be
$1.00
+$2.00
+$3.00
= $6.00
$1.00 ($1.00499999 rounded) + $2.00 ($2.00499999 rounded) + $3.00 ($3.00499999 Rounded) = $6.00