Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2013-08

math round vs banker's round

16 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

David Emerson

Hi all,

I have just discovered that the system.round function has this very odd behavior of rounding towards an even number when the fractional part is .5 -- in the system.round documentation this is described as "banker's rounding"

I do not like this behavior. How can I use a more
mathematically-traditional round function, which always rounds .5 up, and everything below .5 down?

Do I need to write this function myself?

Thanks!
~David

José Mejuto
to David Emerson
David Emerson wrote 12 lines
Hi all, I have just discovered that the system.round function has this very odd behavior of rounding towards an even number when the fractional part is .5 -- in the system.round documentation this is described as "banker's rounding" I do not like this behavior. How can I use a more mathematically-traditional round function, which always rounds .5 up, and everything below .5 down? Do I need to write this function myself?

Hello,

SimpleRoundTo I think.

Maybe documentation should be changed to add SimpleRoundTo in cross referenced functions and note that SimpleRoundTo uses classic round system instead bankers one.

Sven Barth
to David Emerson: I have just discovered that the system.round function has this very odd behavior of…
"David Emerson" wrote
Hi all, I have just discovered that the system.round function has this very odd

behavior of rounding towards an even number when the fractional part is .5 -- in the system.round documentation this is described as "banker's rounding"

I do not like this behavior. How can I use a more

mathematically-traditional round function, which always rounds .5 up, and everything below .5 down?

Do I need to write this function myself?

Take a look at SetRoundMode in unit Math:
http://www.freepascal.org/docs-html/rtl/math/setroundmode.html

Regards,
Sven

Ludo Brands
to Sven Barth
Sven Barth wrote 19 lines
Am 13.08.2013 23:48 schrieb "David Emerson" < >: > > Hi all, > > I have just discovered that the system.round function has this very odd behavior of rounding towards an even number when the fractional part is .5 -- in the system.round documentation this is described as "banker's rounding" > > I do not like this behavior. How can I use a more mathematically-traditional round function, which always rounds .5 up, and everything below .5 down? > > Do I need to write this function myself? Take a look at SetRoundMode in unit Math: http://www.freepascal.org/docs-html/rtl/math/setroundmode.html

None of the round modes gives the result OP wants. Furthermore, SetRoundMode is a runtime setting and

  writeln(round(0.5));
  writeln(round(1.5));

results in
0
2
The compiler hard codes (x64) a movabs $0x0,%rdx and movabs $0x2,%rdx

Ludo

David Emerson
to Sven Barth: behavior of rounding towards an even number when the fractional part is .5 -- in the…

Thanks for the suggestions, guys!

José Mejuto wrote
SimpleRoundTo I think.

But I want an integer result, and this returns a floating point.

Sven Barth wrote
Take a look at SetRoundMode in unit Math: http://www.freepascal.org/docs-html/rtl/math/setroundmode.html

After calling SetRoundMode(rmNearest);
I find that system.round() is still doing banker's rounding. Am I missing something?

I don't see this TfpuRoundingMode mentioned anywhere in the documentation, other than the "get" and "set" functions for the same. What does it effect?

...
Anyway I guess I am going to have to write my own round() function :P

Cheers,
~David.

Ludo Brands
to David Emerson
David Emerson wrote 5 lines
I don't see this TfpuRoundingMode mentioned anywhere in the documentation, other than the "get" and "set" functions for the same. What does it effect?

It sets the 8087 registers and or SSE registers in x86 and x64 systems. The problem is that the bankers mode rounding is the default IEEE 754 rounding and that is what the 8087 and SSE FPU's implements.

For SSE see http://www.rz.uni-karlsruhe.de/rz/docs/VTune/reference/vc148.htm For 8087 see
http://books.google.fr/books?id=QZ9nM0nRQcYC&pg=PA244&lpg=PA244&dq=8087+rounding+mode&source=bl&ots=Vp3tSUsOeJ&sig=Jo7O9KggODpubD_ek5ZhKF-XgNc&hl=en&sa=X&ei=disLUs-zKMODhQeXxYCQCg&ved=0CEgQ6AEwBQ

Ludo

Sven Barth
to David Emerson: I have just discovered that the system.round function has this very odd behavior of…
David Emerson wrote 12 lines
Hi all, I have just discovered that the system.round function has this very odd behavior of rounding towards an even number when the fractional part is .5 -- in the system.round documentation this is described as "banker's rounding" I do not like this behavior. How can I use a more mathematically-traditional round function, which always rounds .5 up, and everything below .5 down? Do I need to write this function myself?

Just checked again, most FPUs only seem to support "banker's rounding", "round up", "round down" and "truncate", so these four are the only ones supported by FPC's and Delphi's rounding mechanism. So if you want normal mathematical rounding then you'll need to write your own function.

Regards,
Sven

Sven Barth
to David Emerson: Thanks for the suggestions, guys! But I want an integer result, and this returns a…
David Emerson wrote 14 lines
Thanks for the suggestions, guys! José Mejuto wrote: > SimpleRoundTo I think. But I want an integer result, and this returns a floating point. Sven Barth wrote: > Take a look at SetRoundMode in unit Math: > http://www.freepascal.org/docs-html/rtl/math/setroundmode.html After calling SetRoundMode(rmNearest); I find that system.round() is still doing banker's rounding. Am I missing something?

rmNearest is banker's rounding.

I don't see this TfpuRoundingMode mentioned anywhere in the documentation, other than the "get" and "set" functions for the same. What does it effect?

Just click on TFPURoundingMode mentioned in the link.

... Anyway I guess I am going to have to write my own round() function :P

Seems so.

Regards,
Sven

Sven Barth
to Ludo Brands: None of the round modes gives the result OP wants. Furthermore, SetRoundMode is a runtime…
Ludo Brands wrote 25 lines
On 08/14/2013 08:03 AM, Sven Barth wrote: > Am 13.08.2013 23:48 schrieb "David Emerson" < > >: >> Hi all, >> >> I have just discovered that the system.round function has this very > odd behavior of rounding towards an even number when the fractional part > is .5 -- in the system.round documentation this is described as > "banker's rounding" >> I do not like this behavior. How can I use a more > mathematically-traditional round function, which always rounds .5 up, > and everything below .5 down? >> Do I need to write this function myself? > Take a look at SetRoundMode in unit Math: > http://www.freepascal.org/docs-html/rtl/math/setroundmode.html > None of the round modes gives the result OP wants. Furthermore, SetRoundMode is a runtime setting and writeln(round(0.5)); writeln(round(1.5)); results in 0 2 The compiler hard codes (x64) a movabs $0x0,%rdx and movabs $0x2,%rdx

There are three problems:
- if you use constants then the compiler will do the rounding at compile time and not take into account the rounding mode (which in my opinion can be considered a bug)
- 0.5 does not always have a direct representation as a floating point value and thus internally it might be 0.4999999 or something like that and thus it will be rounded to 0.4 (see also
http://bugs.freepascal.org/view.php?id=24374 )
- the rounding system and also most FPUs don't support that "normal rounding" the OP wants and thus FPC doesn't implement it either (didn't know up to now that banker's rounding is not the same as the rounding I learned at school...)

Regards,
Sven

Michael Schnell
to Sven Barth
Sven Barth wrote 5 lines
- 0.5 does not always have a direct representation as a floating point value and thus internally it might be 0.4999999 or something like that and thus it will be rounded to 0.4 (see also http://bugs.freepascal.org/view.php?id=24374 )

Hmmm

AFAIU, in hardware / memory, the binary representation of -0.5 is

(sign * mantissa * 2 ** exponent ) = (-1) * 0.5 * 2 ** 1

so this seems to be "exact"

Maybe the compiler does not calculate exactly this value when doing the constant "-0.5". I don't consider this a problem, as IMHO, in fact any attempt to rely on an exact value of a floating point number is erroneous.

-Michael

Jonas Maebe
to Sven Barth: There are three problems: - if you use constants then the compiler will do the rounding…
Sven Barth wrote
- 0.5 does not always have a direct representation as a floating point value and thus internally it might be 0.4999999 or something like that and thus it will be rounded to 0.4 (see also http://bugs.freepascal.org/view.php?id=24374 )

0.5 is one of the values that can always be represented exactly. The fractional part of IEEE 754 floating point numbers is represented as sums of negative powers of 2, i.e. 0.5, 0.25, etc.

Jonas

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 12 lines
On 14 Aug 2013, at 09:38, Sven Barth wrote: > - 0.5 does not always have a direct representation as a floating > point value and thus internally it might be 0.4999999 or something > like that and thus it will be rounded to 0.4 (see > alsohttp://bugs.freepascal.org/view.php?id=24374) 0.5 is one of the values that can always be represented exactly. The fractional part of IEEE 754 floating point numbers is represented as sums of negative powers of 2, i.e. 0.5, 0.25, etc.

It should have been "x.5" instead of "0.5" :)

What's your opinion regarding the point that the compiler does not handle the rounding mode when "Round" is inlined for constants?

Regards,
Sven

Sven Barth
to Michael Schnell: Hmmm AFAIU, in hardware / memory, the binary representation of -0.5 is (sign * mantissa *…
Michael Schnell wrote 18 lines
On 08/14/2013 09:38 AM, Sven Barth wrote: > > - 0.5 does not always have a direct representation as a floating > point value and thus internally it might be 0.4999999 or something > like that and thus it will be rounded to 0.4 (see also > http://bugs.freepascal.org/view.php?id=24374 ) Hmmm AFAIU, in hardware / memory, the binary representation of -0.5 is (sign * mantissa * 2 ** exponent ) = (-1) * 0.5 * 2 ** 1 so this seems to be "exact" Maybe the compiler does not calculate exactly this value when doing the constant "-0.5". I don't consider this a problem, as IMHO, in fact any attempt to rely on an exact value of a floating point number is erroneous.

I wanted to write "x.5" instead of "0.5" :)

Regards,
Sven

Vincent Snijders
to Sven Barth

2013/8/14 Sven Barth

I wanted to write "x.5" instead of "0.5" :)

For any digit x, it still can be represented exactly in binary representation ...

Vincent

Michael Schnell
to Vincent Snijders
Vincent Snijders wrote
For any digit x, it still can be represented exactly in binary representation ...

Nope,
As the bit count of the mantissa is limited to - say - n , with x > 2**(n-1) you will not have an exact representation of x.5.

-Michael