round(2.5)=2

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

round(2.5)=2

Klaus Hartnegg-3
Hi,

The round function behaves different than in TurboPascal, and its
English Wiki page differs from the German page.

When given an argument halfway between to integers, FreePascal rounds to
the nearest even number, TurboPascal always rounds up (except when it is
set to mode $N+, but default is $N-).

The German Wiki pages for Round and SetSoundMode (URLs below) contain a
warning to not use SetRoundMode, because that also affects internal
calculations, and how numbers are stored in variables when they do not
fit with full precision.

How serious is this issue compared with using a different rounding method?

The german pages suggest to use this function instead:
function round(x: Float): Integer;  { requires unit math for 'float' }
begin
   if x > 0 then
       round := trunc(x + 0.5)
   else
       round := -trunc(-x + 0.5);
end;

That is fine, except that I will likely forget it in some unit, and
manually inspecting all units is less reliable than when the compiler
ensures it.

In Turbo-Pascal the browsing feature (search,symbol) of the IDE can show
a list of all places where system.round gets called. The FreePascal IDE
does not show that list (see my other email).

Is there some other reliable(!) way to fix or check this? Maybe a map
file with all functions that got linked into the executable?

The Wiki pages are
- wiki.freepascal.org/Round
- wiki.freepascal.org/Round/de
- wiki.freepascal.org/SetRoundMode
- wiki.freepascal.org/SetRoundMode/de

If the warning is correct, there should also be a note on
https://www.freepascal.org/docs-html/rtl/math/setroundmode.html

thanks,
Klaus
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Bernd Oppolzer

Am 08.06.2018 um 14:47 schrieb Klaus Hartnegg:

> Hi,
>
> The round function behaves different than in TurboPascal, and its
> English Wiki page differs from the German page.
>
> When given an argument halfway between to integers, FreePascal rounds
> to the nearest even number, TurboPascal always rounds up (except when
> it is set to mode $N+, but default is $N-).
>
> The German Wiki pages for Round and SetSoundMode (URLs below) contain
> a warning to not use SetRoundMode, because that also affects internal
> calculations, and how numbers are stored in variables when they do not
> fit with full precision.
>
> How serious is this issue compared with using a different rounding
> method?
>
> The german pages suggest to use this function instead:
> function round(x: Float): Integer;  { requires unit math for 'float' }
> begin
>   if x > 0 then
>       round := trunc(x + 0.5)
>   else
>       round := -trunc(-x + 0.5);
> end;
>
> That is fine, except that I will likely forget it in some unit, and
> manually inspecting all units is less reliable than when the compiler
> ensures it.
>

This is not sufficient, IMO, when using float,
look here:

http://bernd-oppolzer.de/job9i032.htm

> In Turbo-Pascal the browsing feature (search,symbol) of the IDE can
> show a list of all places where system.round gets called. The
> FreePascal IDE does not show that list (see my other email).
>
> Is there some other reliable(!) way to fix or check this? Maybe a map
> file with all functions that got linked into the executable?
>
> The Wiki pages are
> - wiki.freepascal.org/Round
> - wiki.freepascal.org/Round/de
> - wiki.freepascal.org/SetRoundMode
> - wiki.freepascal.org/SetRoundMode/de
>
> If the warning is correct, there should also be a note on
> https://www.freepascal.org/docs-html/rtl/math/setroundmode.html
>
> thanks,
> Klaus
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Michael Schnell
In reply to this post by Klaus Hartnegg-3
There has been a long winding discussion on the German Forum.

IMHO this is not really relevant, as relying on the exact value of a
real number is erroneous, anyway. So a real number never can be
considered to *exactly* *be* 1.5, but just somewhere nearby, and hence
it's not legal to predict hat it is rounded to.

Moreover results of the discussion were:

  - the way of rounding is defined by the CPU hardware, even old Turbo
Pascal executables do banker's rouding on modern hardware.
  - SetRoundMode is not only dangerous, but does not help, anyway, as
there is no mode defining the "intuitive " "non-banker rouding" method.
  - (some versions of) Turbo Pascal had a soft-real library that did
"intuitive" rounding.

-Michael
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Mattias Gaertner
On Mon, 11 Jun 2018 10:01:13 +0200
Michael Schnell <[hidden email]> wrote:

> There has been a long winding discussion on the German Forum.
>
> IMHO this is not really relevant, as relying on the exact value of a
> real number is erroneous, anyway. So a real number never can be
> considered to *exactly* *be* 1.5, but just somewhere nearby, and hence
> it's not legal to predict hat it is rounded to.

Floats can represent 1.5 exactly.

Mattias
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Michael Schnell
On 12.06.2018 09:01, Mattias Gaertner wrote:
> Floats can represent 1.5 exactly.
Of course I do know how the binary representation of floats is done on
X86 and similar architectures, and hence that same provides a bit
combination that exactly defines 1.5.

That is why I did say *relying* on the exact value of a real number is
erroneous. (Supposedly with the common archs, no representation of a
rational a/b will be exact but those with b = 2**n).

But for an application programmer it should not be considered common
knowledge, that on the architecture his program is to run on, 3/2 can be
represented exactly while 2/3 can't.

That is why an application programmer should be trained not to do any
assumptions which float value is to be considered  to be exact and which
is not.

-Michael
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Klaus Hartnegg-3
In reply to this post by Mattias Gaertner
Am 12.06.2018 um 09:01 schrieb Mattias Gaertner:
>> IMHO this is not really relevant, as relying on the exact value of a
>> real number is erroneous, anyway. So a real number never can be
>> considered to *exactly* *be* 1.5, but just somewhere nearby, and hence
>> it's not legal to predict hat it is rounded to.
>
> Floats can represent 1.5 exactly.

Yes. And such numbers do pop up all the time.

That mathematical theory is only valid for measured values. If measured
with unlimited precision.

Then you could arbitrarily define round(1.5)=9, and nobody would ever
notice. Because the chance would be zero that a variable ever has that
exact value.

But we do not only store measured values in variables. And we often
measure with low precision. That's why this is relevant.

When I got different results from the FreePascal port of my source, it
took me quite a while until I found the cause in the compiler. Because
that is typically not the first place to look at.

Klaus
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Klaus Hartnegg-3
In reply to this post by Michael Schnell
Am 11.06.2018 um 10:01 schrieb Michael Schnell:
>  - the way of rounding is defined by the CPU hardware, even old Turbo
> Pascal executables do banker's rouding on modern hardware.

No, it does not depend on the hardware, but on the setting of $N. Turbo
Pascal with $N+ rounds like FreePascal. But the default is $N-. In this
mode Turbo Pascal always rounds up.

var
   a : real;
begin
   a := 35;
   writeln (round(a*1.1));
end.

FreePascal: 38
Turbo Pascal: 39

And when the compiler precalculates a constant expression, it always
rounds up as well, regardless of $N.

Nobody expects that increasing a number by 10% will depend on whether
the resulting number will be close to an even integer. That feels
completely erratic.

This behaviour does have advantages in the special case of adding up
many rounded numbers, but it ruins the graphics output of my software.
It should at least be configurable. And in {$mode tp} it should behave
like Turbo Pascal, because that's what this mode is made for.

>   - SetRoundMode is not only dangerous, but does not help, anyway, as
> there is no mode defining the "intuitive " "non-banker rouding" method.

That's why I'm looking for a better solution. The the only *reliable*
solution appears to be compiling a modified version of FreePascal.

Klaus
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Jonas Maebe-3
On 12/06/18 23:12, Klaus Hartnegg wrote:
> This behaviour does have advantages in the special case of adding up
> many rounded numbers, but it ruins the graphics output of my software.
> It should at least be configurable. And in {$mode tp} it should behave
> like Turbo Pascal, because that's what this mode is made for.

The basic issue is that FPC doesn't support the 6 byte real type used by
TP in {$n-}, nor the associated behaviours such as rounding,
range/precision cut-offs etc. FPC indeed can only support TP {$n+} mode
compatibility at this time (and even that is not always exact, as it
depends on the FPU precision support by the hardware and OS).


Jonas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Klaus Hartnegg-3
Am 12.06.2018 um 23:24 schrieb Jonas Maebe:

> On 12/06/18 23:12, Klaus Hartnegg wrote:
>> This behaviour does have advantages in the special case of adding up
>> many rounded numbers, but it ruins the graphics output of my software.
>> It should at least be configurable. And in {$mode tp} it should behave
>> like Turbo Pascal, because that's what this mode is made for.
>
> The basic issue is that FPC doesn't support the 6 byte real type used by
> TP in {$n-}, nor the associated behaviours such as rounding,
> range/precision cut-offs etc. FPC indeed can only support TP {$n+} mode
> compatibility at this time (and even that is not always exact, as it
> depends on the FPU precision support by the hardware and OS).

Nevertheless it could offer an option to use the other rounding method.

Yes, there would still be deviations in some math results, because of
the different precision. But these deviations are much smaller than
those from the other rounding method.

Klaus
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Wolf

Why not ask the CPU to do the rounding? This is what Intel offers in volume 1 of the Intel ® 64 and IA-32 Architectures Software Developer's Manual:


4.8.4.1
 Rounding Control (RC) Fields
In the Intel 64 and IA-32 architectures, the rounding mode is controlled by a 2-bit rounding-control (RC) field
(Table 4-8 shows the encoding of this field). The RC field is implemented in two different locations:

 x87 FPU control register (bits 10 and 11)

 The MXCSR register (bits 13 and 14)
Although these two RC fields perform the same function, they control rounding for different execution environ-
ments within the processor. The RC field in the x87 FPU control register controls rounding for computations
performed with the x87 FPU instructions; the RC field in the MXCSR register controls rounding for SIMD floating-
point computations performed with the SSE/SSE2 instructions.


Do you want more?

Wolf


On 13/06/2018 09:58, Klaus Hartnegg wrote:
Am 12.06.2018 um 23:24 schrieb Jonas Maebe:
On 12/06/18 23:12, Klaus Hartnegg wrote:
This behaviour does have advantages in the special case of adding up many rounded numbers, but it ruins the graphics output of my software. It should at least be configurable. And in {$mode tp} it should behave like Turbo Pascal, because that's what this mode is made for.

The basic issue is that FPC doesn't support the 6 byte real type used by TP in {$n-}, nor the associated behaviours such as rounding, range/precision cut-offs etc. FPC indeed can only support TP {$n+} mode compatibility at this time (and even that is not always exact, as it depends on the FPU precision support by the hardware and OS).

Nevertheless it could offer an option to use the other rounding method.

Yes, there would still be deviations in some math results, because of the different precision. But these deviations are much smaller than those from the other rounding method.

Klaus
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Michael Schnell
In reply to this post by Klaus Hartnegg-3
On 12.06.2018 23:12, Klaus Hartnegg wrote:
>
> No, it does not depend on the hardware, but on the setting of $N.
> Turbo Pascal with $N+ rounds like FreePascal. But the default is $N-.
> In this mode Turbo Pascal always rounds up.
>
What exactly does $N in Turbo pascal mean ? Obviously it in this case it
(at least for round() ) does not simply use the hardware for the 
calculation (as fpc does).

-Michael
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Michael Schnell
In reply to this post by Klaus Hartnegg-3
On 12.06.2018 23:12, Klaus Hartnegg wrote:
> The only *reliable* solution appears to be compiling a modified
> version of FreePascal.
>
It would make the round function a lot slower not to simply rely on the
hardware.

And in fact the only *reliable* solution is *not ever* to rely on exact
values of floats.

-Michael

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Michael Schnell
In reply to this post by Klaus Hartnegg-3

On 12.06.2018 23:12, Klaus Hartnegg wrote:
>   writeln (round(a*1.1));

As with usual float formats 1.1 can't be represented exactly, the result
can't be considered any precise value.

-Michael
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Free Pascal - General mailing list
In reply to this post by Wolf
Wolf <[hidden email]> schrieb am Mi., 13. Juni 2018, 09:27:

Why not ask the CPU to do the rounding? This is what Intel offers in volume 1 of the Intel ® 64 and IA-32 Architectures Software Developer's Manual:

4.8.4.1
 Rounding Control (RC) Fields
In the Intel 64 and IA-32 architectures, the rounding mode is controlled by a 2-bit rounding-control (RC) field
(Table 4-8 shows the encoding of this field). The RC field is implemented in two different locations:

 x87 FPU control register (bits 10 and 11)

 The MXCSR register (bits 13 and 14)
Although these two RC fields perform the same function, they control rounding for different execution environ-
ments within the processor. The RC field in the x87 FPU control register controls rounding for computations
performed with the x87 FPU instructions; the RC field in the MXCSR register controls rounding for SIMD floating-
point computations performed with the SSE/SSE2 instructions.


Do you want more?

Which is what FPC already provides with SetRoundMode() in unit Math. 

As long as one changes the rounding mode only locally for some calculations and restores it afterwards there should be no problem (the rounding mode can be considered as thread specific as well). 

Regards, 
Sven

PS: please don't add images as inline content, the archive can't display them correctly. 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Santiago A.
In reply to this post by Klaus Hartnegg-3
El 12/06/2018 a las 23:12, Klaus Hartnegg escribió:

> Am 11.06.2018 um 10:01 schrieb Michael Schnell:
>>  - the way of rounding is defined by the CPU hardware, even old Turbo
>> Pascal executables do banker's rouding on modern hardware.
>
> No, it does not depend on the hardware, but on the setting of $N.
> Turbo Pascal with $N+ rounds like FreePascal. But the default is $N-.
> In this mode Turbo Pascal always rounds up.
>
> var
>   a : real;
> begin
>   a := 35;
>   writeln (round(a*1.1));
> end.
>
> FreePascal: 38
> Turbo Pascal: 39
>
> And when the compiler precalculates a constant expression, it always
> rounds up as well, regardless of $N.
>
> Nobody expects that increasing a number by 10% will depend on whether
> the resulting number will be close to an even integer. That feels
> completely erratic.

I don't feel it is completely erratic. If instead of 35 it were 1000035
would you mind if the result were 1100038 or 1100039? When you round
small numbers, relative rounding errors skyrocket, that is a fact of
life. Any software must be aware of this and live with it.

>
> This behaviour does have advantages in the special case of adding up
> many rounded numbers, but it ruins the graphics output of my software.
> It should at least be configurable. And in {$mode tp} it should behave
> like Turbo Pascal, because that's what this mode is made for.
>
>>   - SetRoundMode is not only dangerous, but does not help, anyway, as
>> there is no mode defining the "intuitive " "non-banker rouding" method.
>
> That's why I'm looking for a better solution. The the only *reliable*
> solution appears to be compiling a modified version of FreePascal.
I think that is even more dangerous. Who knows how many internal
freepascal will fail when you change rounding. It would be better to
review  software to check  why it needs always round floor for 0.5

>
> Klaus
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


--
Saludos

Santiago A.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Marco van de Voort
In reply to this post by Free Pascal - General mailing list
In our previous episode, Sven Barth via fpc-pascal said:
> Which is what FPC already provides with SetRoundMode() in unit Math.
>
> As long as one changes the rounding mode only locally for some calculations
> and restores it afterwards there should be no problem (the rounding mode
> can be considered as thread specific as well).

Or soft fpu. (-Cfsoft). Or is that only for 16-bit mode ?
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Florian Klämpfl


Am 13. Juni 2018 5:39:08 nachm. schrieb [hidden email] (Marco van de Voort):

> In our previous episode, Sven Barth via fpc-pascal said:
>> Which is what FPC already provides with SetRoundMode() in unit Math.
>>
>> As long as one changes the rounding mode only locally for some calculations
>> and restores it afterwards there should be no problem (the rounding mode
>> can be considered as thread specific as well).
>
> Or soft fpu. (-Cfsoft). Or is that only for 16-bit mode ?

What does it change? -Cfsoft is also IEEE compliant.

> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal



_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Marco van de Voort
In our previous episode, Florian Kl?mpfl said:

> > In our previous episode, Sven Barth via fpc-pascal said:
> >> Which is what FPC already provides with SetRoundMode() in unit Math.
> >>
> >> As long as one changes the rounding mode only locally for some calculations
> >> and restores it afterwards there should be no problem (the rounding mode
> >> can be considered as thread specific as well).
> >
> > Or soft fpu. (-Cfsoft). Or is that only for 16-bit mode ?
>
> What does it change? -Cfsoft is also IEEE compliant.

I thought that Nikolai was working on a 48-bit TP real soft fpu?
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

Florian Klämpfl
Am 13.06.2018 um 22:19 schrieb Marco van de Voort:

> In our previous episode, Florian Kl?mpfl said:
>>> In our previous episode, Sven Barth via fpc-pascal said:
>>>> Which is what FPC already provides with SetRoundMode() in unit Math.
>>>>
>>>> As long as one changes the rounding mode only locally for some calculations
>>>> and restores it afterwards there should be no problem (the rounding mode
>>>> can be considered as thread specific as well).
>>>
>>> Or soft fpu. (-Cfsoft). Or is that only for 16-bit mode ?
>>
>> What does it change? -Cfsoft is also IEEE compliant.
>
> I thought that Nikolai was working on a 48-bit TP real soft fpu?

Not that I am aware of? At least I cannot remember that I have seen any code.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: round(2.5)=2

wkitty42
In reply to this post by Michael Schnell
On 06/13/2018 04:17 AM, Michael Schnell wrote:
> On 12.06.2018 23:12, Klaus Hartnegg wrote:
>>
>> No, it does not depend on the hardware, but on the setting of $N. Turbo Pascal
>> with $N+ rounds like FreePascal. But the default is $N-. In this mode Turbo
>> Pascal always rounds up.
>>
> What exactly does $N in Turbo pascal mean ? Obviously it in this case it (at
> least for round() ) does not simply use the hardware for the calculation (as fpc
> does).

$N switches between using "software code" OR using "a math coprocessor chip" for
real-type processing... transcribing the following while reading it off another
machine running TP6's Turbo CTRL-F1 screen... typos are mine...


{$N}
Numeric Processing Switch
=========================
Switches between the two different models of floating-point code generation
supported by Turbo Pascal

   Syntax:  {$N+} or {$N-}
   Default: {$N-}
   Type:    Global
   Menus:   [X] 8087/80287


The {$N-} State
===============
In the {$N-} state, Turbo Pascal generates code to perform all real-type
calculations in software by calling run-time library routines.


The {$N+} State
===============
In the {$N+} state, Turbo Pascal generates code to perform all real-type
calculations using the 8087 numeric coprocessor.

* NOTE: You can also use the {$E+} directive to emulate the 8087. This gives you
access to the IEEE floating-point types without requiring that you install an
8087 chip.




--
  NOTE: No off-list assistance is given without prior approval.
        *Please keep mailing list traffic on the list unless*
        *a signed and pre-paid contract is in effect with us.*
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal