Why is the result of RoundTo(87.285, -2) => 87.28
Asked Answered
M

2

22

I expected that the result would be 87.29. I also tried SimpleRoundTo, but produces the same result.

In the help there is also a "strange" example: ms-help://embarcadero.rs2010/vcl/Math.RoundTo.html

RoundTo(1.235, -2) => 1.24
RoundTo(1.245, -2) => 1.24 //???

Does anybody know which function I need to get the result of 87.29? I mean: If the last digit >= 5 round up, if < 5 round down. As taught in the school :)

I use Delphi2010, and SetRoundMode(rmNearest). I also tried with rmTruncate. The value 87.285 is stored in a double variable.

Also strange:

SimpleRoundTo(87.285, -2) => 87.29

but

x := 87.285; //double
SimpleRoundTo(x, -2) => 87.28
Milliard answered 4/3, 2011 at 8:14 Comment(1)
As discussed by David and Rob below, the above comment isn't as great as it might appear at first.Rattoon
S
21

87.285 is not exactly representable and the nearest double is slightly smaller.

The classic reference on floating point is What Every Computer Scientist Should Know About Floating- Point Arithmetic.

For currency based calculations, if indeed this is, you should use a base 10 number type rather than base 2 floating point. In Delphi that means Currency.

Sourwood answered 4/3, 2011 at 8:28 Comment(6)
+1. Rounding is usually critical only when dealing with money, and for money we should use Currency. Currency can represent that number and rounding will properly round it.Telesis
I seem to point people to that article all the time. People seem to think that floating point numbers have capabilities beyond their real capabilities. Like the ability to represent one third. And bankers rounding surprises lots of people too.Olney
Currency is always a base 2 value, but is an integer value (although managed through the FPU, IIRC) automatically scaled to four decimals (fixed). Binary-coded decimals are implemented using TBCD. It can easy manipulated using Variants (see VarFMTBCDCreate).Epigone
@Idsandon I think Currency is effectively a base 10 fixed point value, implemented using integers.Sourwood
Currency has a 2^63 range (before scaling, scaling just set where the decimal point is within the number) , thereby IMHO it looks a base 2 type :) TBCD has a number from 0 to 9 per nibble in its Fraction field, and looks a base 10 type.Epigone
@Idsandon All modern computers are base 2 at the lowest level. The Delphi Currency type uses a base 10 scaling which gives it the base-10 characteristics of representability for currency values. That's what I was trying to get across.Sourwood
C
28

The exact value 87.285 is not representable as a floating-point value in Delphi. A page on my Web site shows what that value really is, as Extended, Double, and Single:

87.285 = + 87.28500 00000 00000 00333 06690 73875 46962 12708 95004 27246 09375
87.285 = + 87.28499 99999 99996 58939 48683 51519 10781 86035 15625
87.285 = + 87.28500 36621 09375

By default, floating-point literals in Delphi have type Extended, and as you can see, the Extended version of your number is slightly higher than 87.285, so it is correct that rounding to nearest would round up. But as a Double, the real number is slightly lower. That's why you get the number you expected if you explicitly store the number in a Double variable before calling RoundTo. There are overloads of that function for each of Delphi's floating-point types.

Cataplexy answered 4/3, 2011 at 9:21 Comment(2)
+1 Love that page on your website! Automatic answers to all such questions!Sourwood
+1 That great page was the main resaon why I got interested in Good Delphi Blogs!Rattoon
S
21

87.285 is not exactly representable and the nearest double is slightly smaller.

The classic reference on floating point is What Every Computer Scientist Should Know About Floating- Point Arithmetic.

For currency based calculations, if indeed this is, you should use a base 10 number type rather than base 2 floating point. In Delphi that means Currency.

Sourwood answered 4/3, 2011 at 8:28 Comment(6)
+1. Rounding is usually critical only when dealing with money, and for money we should use Currency. Currency can represent that number and rounding will properly round it.Telesis
I seem to point people to that article all the time. People seem to think that floating point numbers have capabilities beyond their real capabilities. Like the ability to represent one third. And bankers rounding surprises lots of people too.Olney
Currency is always a base 2 value, but is an integer value (although managed through the FPU, IIRC) automatically scaled to four decimals (fixed). Binary-coded decimals are implemented using TBCD. It can easy manipulated using Variants (see VarFMTBCDCreate).Epigone
@Idsandon I think Currency is effectively a base 10 fixed point value, implemented using integers.Sourwood
Currency has a 2^63 range (before scaling, scaling just set where the decimal point is within the number) , thereby IMHO it looks a base 2 type :) TBCD has a number from 0 to 9 per nibble in its Fraction field, and looks a base 10 type.Epigone
@Idsandon All modern computers are base 2 at the lowest level. The Delphi Currency type uses a base 10 scaling which gives it the base-10 characteristics of representability for currency values. That's what I was trying to get across.Sourwood

© 2022 - 2024 — McMap. All rights reserved.