pharo-users@lists.pharo.org

Any question about pharo is welcome

View all threads

Rounding in Floats

EM
Esteban Maringolo
Tue, Sep 8, 2020 3:45 AM

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip>

The systems that print 7.1 are LYING to you,
and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: > > "7.1 roundTo: 0.1 should return 7.1" > You're still not getting it. I was until Konrad explained it. > Binary floating point CANNOT represent either of those numbers. > You seem to be assuming that Pharo is making some mistake. > It isn't. All it is doing is refusing to lie to you. <snip> > The systems that print 7.1 are LYING to you, > and Pharo is not. I'm not assuming a mistake from Pharo, I had a wrong expectation what to get if I round to that precision. I don't know whether other systems lie or simply fulfill user expectations, if you send the #roundTo: to a float, I did expect to get a number with the same precision. That is my expectation as a user. As in the other thread I expected two scaled decimals that are printed equal to also be compared as equal (which they don't). Whether there is a good reason for those behaviors is beyond my current comprehension, but it certainly doesn't follow the "principle of least surprise". In any case, the method proposed by Tomohiro solved my issues. Regards, Esteban A. Maringolo
RO
Richard O'Keefe
Tue, Sep 15, 2020 1:13 PM

If you are going to use floating point numbers in any programming
language, Pharo included, you need to understand something about
them.  Things like

  • the relevant precision is fixed; a Float in Pharo is always
    a 64-bit IEEE floating-point number, which amongst other things
    means (to a first approximation) 54 binary digits of precision.
    It doesn't make the slightest amount of difference how many
    decimal digits you use when writing the number, the precision
    is always 54 binary digits.  So you did get the precision
    out of rounding that you put in, it's just that the precision
    you put in was not what you thought it was.
  • almost all modern architectures offer BINARY arithmetic, not
    decimal.  (The main exceptions are IBM z/series and IBM POWER,
    which offer binary and decimal.)  Rounding a number to n
    decimals is ALWAYS problematic using binary floats.  This has
    little or nothing to do with Smalltalk: it's the hardware.
    (This is why you are advised to keep money in cents, not dollars.)
  • Again, this is NOT a language issue, it is a hardware issue.
    IF you understand how binary floating point arithmetic works,
    then the arithmetic you get in C or R or Smalltalk or Matlab
    does not surprise you at all.
    If you DON'T understand how binary floating point arithmetic works,
    the hardware will get you sooner or later.
  • ScaledDecimal in Pharo didn't have to violate the principle of
    least surprise, but it does, big time.
  • It would be really nice if Pharo offered true decimal arithmetic
    as an option.  There may already be a package for this.

On Tue, 8 Sep 2020 at 15:46, Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip>

The systems that print 7.1 are LYING to you,
and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

If you are going to use floating point numbers in any programming language, Pharo included, you need to understand something about them. Things like - the relevant precision is *fixed*; a Float in Pharo is *always* a 64-bit IEEE floating-point number, which amongst other things means (to a first approximation) 54 binary digits of precision. It doesn't make the slightest amount of difference how many decimal digits you use when writing the number, the precision is *always* 54 binary digits. So you *did* get the precision out of rounding that you put in, it's just that the precision you put in was not what you thought it was. - almost all modern architectures offer BINARY arithmetic, not decimal. (The main exceptions are IBM z/series and IBM POWER, which offer binary *and* decimal.) Rounding a number to n decimals is ALWAYS problematic using binary floats. This has little or nothing to do with Smalltalk: it's the hardware. (This is why you are advised to keep money in cents, not dollars.) - Again, this is NOT a language issue, it is a hardware issue. IF you understand how binary floating point arithmetic works, then the arithmetic you get in C or R or Smalltalk or Matlab does not surprise you at all. If you DON'T understand how binary floating point arithmetic works, the hardware will *get* you sooner or later. - ScaledDecimal in Pharo didn't have to violate the principle of least surprise, but it does, big time. - It would be really nice if Pharo offered true decimal arithmetic as an option. There may already be a package for this. On Tue, 8 Sep 2020 at 15:46, Esteban Maringolo <emaringolo@gmail.com> wrote: > On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: > > > > "7.1 roundTo: 0.1 should return 7.1" > > You're still not getting it. > > I was until Konrad explained it. > > > Binary floating point CANNOT represent either of those numbers. > > You seem to be assuming that Pharo is making some mistake. > > It isn't. All it is doing is refusing to lie to you. > <snip> > > The systems that print 7.1 are LYING to you, > > and Pharo is not. > > I'm not assuming a mistake from Pharo, I had a wrong expectation what > to get if I round to that precision. > I don't know whether other systems lie or simply fulfill user > expectations, if you send the #roundTo: to a float, I did expect to > get a number with the same precision. > That is my expectation as a user. As in the other thread I expected > two scaled decimals that are printed equal to also be compared as > equal (which they don't). > > Whether there is a good reason for those behaviors is beyond my > current comprehension, but it certainly doesn't follow the "principle > of least surprise". > > In any case, the method proposed by Tomohiro solved my issues. > > Regards, > > Esteban A. Maringolo > >
EM
Esteban Maringolo
Mon, Jun 14, 2021 8:44 PM

I'm coming back to this because I've been bitten by these floating
points things again.

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)

It will produce:
4.499999999999997

Which, when rounded, will produce 4.

In other places [2] I do the same simple addition and subtraction it
produces 4.5, that when rounded will produce 5.

I know now that Pharo doesn't lie to me while other systems do, and
all that Richard pointed to before.

The issue here is that I'm following some calculation formula that was
defined in some of the "other" systems, and so when I follow such a
formula I get these edgy cases where my system produces a different
output.

In this case the formula is for golf handicap calculations, and it
caused my system to give 4 instead of 5 to a player, resulting in
giving the first place to a player other than the one deserved.
It was no big deal (it's not The Masters), but these cases appear from
time to time.

Is there any way to "configure" the floating point calculation to
behave as the "other systems"?

What is the best way to anticipate these situations, am I the only one
being bitten by these issues?

Thanks in advance for any hints about these problems.

Best regards,

[1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo.
[2] VisualWorks, VAST, Excel, VB and all calculators I tried

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip> > The systems that print 7.1 are LYING to you, > and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

I'm coming back to this because I've been bitten by these floating points things again. If in Pharo [1] you do: a := 6.7 + (32.8 - 35) It will produce: 4.499999999999997 Which, when rounded, will produce 4. In other places [2] I do the same simple addition and subtraction it produces 4.5, that when rounded will produce 5. I know now that Pharo doesn't lie to me while other systems do, and all that Richard pointed to before. The issue here is that I'm following some calculation formula that was defined in some of the "other" systems, and so when I follow such a formula I get these edgy cases where my system produces a different output. In this case the formula is for golf handicap calculations, and it caused my system to give 4 instead of 5 to a player, resulting in giving the first place to a player other than the one deserved. It was no big deal (it's not The Masters), but these cases appear from time to time. Is there any way to "configure" the floating point calculation to behave as the "other systems"? What is the best way to anticipate these situations, am I the only one being bitten by these issues? Thanks in advance for any hints about these problems. Best regards, [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo. [2] VisualWorks, VAST, Excel, VB and all calculators I tried Esteban A. Maringolo On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo <emaringolo@gmail.com> wrote: > > On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: > > > > "7.1 roundTo: 0.1 should return 7.1" > > You're still not getting it. > > I was until Konrad explained it. > > > Binary floating point CANNOT represent either of those numbers. > > You seem to be assuming that Pharo is making some mistake. > > It isn't. All it is doing is refusing to lie to you. > <snip> > > The systems that print 7.1 are LYING to you, > > and Pharo is not. > > I'm not assuming a mistake from Pharo, I had a wrong expectation what > to get if I round to that precision. > I don't know whether other systems lie or simply fulfill user > expectations, if you send the #roundTo: to a float, I did expect to > get a number with the same precision. > That is my expectation as a user. As in the other thread I expected > two scaled decimals that are printed equal to also be compared as > equal (which they don't). > > Whether there is a good reason for those behaviors is beyond my > current comprehension, but it certainly doesn't follow the "principle > of least surprise". > > In any case, the method proposed by Tomohiro solved my issues. > > Regards, > > Esteban A. Maringolo
SV
Sven Van Caekenberghe
Mon, Jun 14, 2021 9:23 PM

On 14 Jun 2021, at 22:44, Esteban Maringolo emaringolo@gmail.com wrote:

I'm coming back to this because I've been bitten by these floating
points things again.

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)

It will produce:
4.499999999999997

Which, when rounded, will produce 4.

But,

a roundTo: 0.1 "=> 4.5"

In other places [2] I do the same simple addition and subtraction it
produces 4.5, that when rounded will produce 5.

I know now that Pharo doesn't lie to me while other systems do, and
all that Richard pointed to before.

The issue here is that I'm following some calculation formula that was
defined in some of the "other" systems, and so when I follow such a
formula I get these edgy cases where my system produces a different
output.

In this case the formula is for golf handicap calculations, and it
caused my system to give 4 instead of 5 to a player, resulting in
giving the first place to a player other than the one deserved.
It was no big deal (it's not The Masters), but these cases appear from
time to time.

Is there any way to "configure" the floating point calculation to
behave as the "other systems"?

What is the best way to anticipate these situations, am I the only one
being bitten by these issues?

Thanks in advance for any hints about these problems.

Best regards,

[1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo.
[2] VisualWorks, VAST, Excel, VB and all calculators I tried

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip>

The systems that print 7.1 are LYING to you,
and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

> On 14 Jun 2021, at 22:44, Esteban Maringolo <emaringolo@gmail.com> wrote: > > I'm coming back to this because I've been bitten by these floating > points things again. > > If in Pharo [1] you do: > a := 6.7 + (32.8 - 35) > > It will produce: > 4.499999999999997 > > Which, when rounded, will produce 4. But, a roundTo: 0.1 "=> 4.5" > In other places [2] I do the same simple addition and subtraction it > produces 4.5, that when rounded will produce 5. > > I know now that Pharo doesn't lie to me while other systems do, and > all that Richard pointed to before. > > The issue here is that I'm following some calculation formula that was > defined in some of the "other" systems, and so when I follow such a > formula I get these edgy cases where my system produces a different > output. > > In this case the formula is for golf handicap calculations, and it > caused my system to give 4 instead of 5 to a player, resulting in > giving the first place to a player other than the one deserved. > It was no big deal (it's not The Masters), but these cases appear from > time to time. > > Is there any way to "configure" the floating point calculation to > behave as the "other systems"? > > What is the best way to anticipate these situations, am I the only one > being bitten by these issues? > > Thanks in advance for any hints about these problems. > > > Best regards, > > [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo. > [2] VisualWorks, VAST, Excel, VB and all calculators I tried > > > > Esteban A. Maringolo > > On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo <emaringolo@gmail.com> wrote: >> >> On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: >>> >>> "7.1 roundTo: 0.1 should return 7.1" >>> You're still not getting it. >> >> I was until Konrad explained it. >> >>> Binary floating point CANNOT represent either of those numbers. >>> You seem to be assuming that Pharo is making some mistake. >>> It isn't. All it is doing is refusing to lie to you. >> <snip> >>> The systems that print 7.1 are LYING to you, >>> and Pharo is not. >> >> I'm not assuming a mistake from Pharo, I had a wrong expectation what >> to get if I round to that precision. >> I don't know whether other systems lie or simply fulfill user >> expectations, if you send the #roundTo: to a float, I did expect to >> get a number with the same precision. >> That is my expectation as a user. As in the other thread I expected >> two scaled decimals that are printed equal to also be compared as >> equal (which they don't). >> >> Whether there is a good reason for those behaviors is beyond my >> current comprehension, but it certainly doesn't follow the "principle >> of least surprise". >> >> In any case, the method proposed by Tomohiro solved my issues. >> >> Regards, >> >> Esteban A. Maringolo
SV
Sven Van Caekenberghe
Mon, Jun 14, 2021 9:30 PM

BTW, I recently wrote my own float printer, as an experiment.

NeoJSONFloatPrinter lowPrecision print: a.

=> 4.5

What I wanted was a human friendly, compact float printer, that tries to go for the shortest, simplest number. It prefers integers and goes to scientific notation when needed, while limiting the precision. Maybe it is interesting to look at the code.

But I am far from an expert.

On 14 Jun 2021, at 23:23, Sven Van Caekenberghe sven@stfx.eu wrote:

On 14 Jun 2021, at 22:44, Esteban Maringolo emaringolo@gmail.com wrote:

I'm coming back to this because I've been bitten by these floating
points things again.

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)

It will produce:
4.499999999999997

Which, when rounded, will produce 4.

But,

a roundTo: 0.1 "=> 4.5"

In other places [2] I do the same simple addition and subtraction it
produces 4.5, that when rounded will produce 5.

I know now that Pharo doesn't lie to me while other systems do, and
all that Richard pointed to before.

The issue here is that I'm following some calculation formula that was
defined in some of the "other" systems, and so when I follow such a
formula I get these edgy cases where my system produces a different
output.

In this case the formula is for golf handicap calculations, and it
caused my system to give 4 instead of 5 to a player, resulting in
giving the first place to a player other than the one deserved.
It was no big deal (it's not The Masters), but these cases appear from
time to time.

Is there any way to "configure" the floating point calculation to
behave as the "other systems"?

What is the best way to anticipate these situations, am I the only one
being bitten by these issues?

Thanks in advance for any hints about these problems.

Best regards,

[1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo.
[2] VisualWorks, VAST, Excel, VB and all calculators I tried

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip>

The systems that print 7.1 are LYING to you,
and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

BTW, I recently wrote my own float printer, as an experiment. NeoJSONFloatPrinter lowPrecision print: a. => 4.5 What I wanted was a human friendly, compact float printer, that tries to go for the shortest, simplest number. It prefers integers and goes to scientific notation when needed, while limiting the precision. Maybe it is interesting to look at the code. But I am far from an expert. > On 14 Jun 2021, at 23:23, Sven Van Caekenberghe <sven@stfx.eu> wrote: > > > >> On 14 Jun 2021, at 22:44, Esteban Maringolo <emaringolo@gmail.com> wrote: >> >> I'm coming back to this because I've been bitten by these floating >> points things again. >> >> If in Pharo [1] you do: >> a := 6.7 + (32.8 - 35) >> >> It will produce: >> 4.499999999999997 >> >> Which, when rounded, will produce 4. > > But, > > a roundTo: 0.1 "=> 4.5" > >> In other places [2] I do the same simple addition and subtraction it >> produces 4.5, that when rounded will produce 5. >> >> I know now that Pharo doesn't lie to me while other systems do, and >> all that Richard pointed to before. >> >> The issue here is that I'm following some calculation formula that was >> defined in some of the "other" systems, and so when I follow such a >> formula I get these edgy cases where my system produces a different >> output. >> >> In this case the formula is for golf handicap calculations, and it >> caused my system to give 4 instead of 5 to a player, resulting in >> giving the first place to a player other than the one deserved. >> It was no big deal (it's not The Masters), but these cases appear from >> time to time. >> >> Is there any way to "configure" the floating point calculation to >> behave as the "other systems"? >> >> What is the best way to anticipate these situations, am I the only one >> being bitten by these issues? >> >> Thanks in advance for any hints about these problems. >> >> >> Best regards, >> >> [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo. >> [2] VisualWorks, VAST, Excel, VB and all calculators I tried >> >> >> >> Esteban A. Maringolo >> >> On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo <emaringolo@gmail.com> wrote: >>> >>> On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: >>>> >>>> "7.1 roundTo: 0.1 should return 7.1" >>>> You're still not getting it. >>> >>> I was until Konrad explained it. >>> >>>> Binary floating point CANNOT represent either of those numbers. >>>> You seem to be assuming that Pharo is making some mistake. >>>> It isn't. All it is doing is refusing to lie to you. >>> <snip> >>>> The systems that print 7.1 are LYING to you, >>>> and Pharo is not. >>> >>> I'm not assuming a mistake from Pharo, I had a wrong expectation what >>> to get if I round to that precision. >>> I don't know whether other systems lie or simply fulfill user >>> expectations, if you send the #roundTo: to a float, I did expect to >>> get a number with the same precision. >>> That is my expectation as a user. As in the other thread I expected >>> two scaled decimals that are printed equal to also be compared as >>> equal (which they don't). >>> >>> Whether there is a good reason for those behaviors is beyond my >>> current comprehension, but it certainly doesn't follow the "principle >>> of least surprise". >>> >>> In any case, the method proposed by Tomohiro solved my issues. >>> >>> Regards, >>> >>> Esteban A. Maringolo
EM
Esteban Maringolo
Mon, Jun 14, 2021 11:03 PM

Hi Sven,

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)
It will produce:
4.499999999999997
Which, when rounded, will produce 4.

But,
a roundTo: 0.1 "=> 4.5"

Sure, but what initiated this thread was a reference to roundTo: 0.1
which produced a "wrong" output.

(9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005"
7.1 roundTo: 0.1 "=> 7.1000000000000005"

However, at this point I know that Pharo "does the right, raw, thing"
(at least compared to other mainstream languages), but it still
produces a surprise effect.

In particular when people go to Excel to "check that your system does
the right thing", uses the same formula and it gives a different
result to them. Then open a calculator (or a physical one) and it
gives the same number as Excel. So an hour after the fact you're
arguing about floating point implementations to non-technical people
:-)

Regards!

Esteban A. Maringolo

Hi Sven, > > If in Pharo [1] you do: > > a := 6.7 + (32.8 - 35) > > It will produce: > > 4.499999999999997 > > Which, when rounded, will produce 4. > But, > a roundTo: 0.1 "=> 4.5" Sure, but what initiated this thread was a reference to roundTo: 0.1 which produced a "wrong" output. (9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005" 7.1 roundTo: 0.1 "=> 7.1000000000000005" However, at this point I know that Pharo "does the right, raw, thing" (at least compared to other mainstream languages), but it still produces a surprise effect. In particular when people go to Excel to "check that your system does the right thing", uses the same formula and it gives a different result to them. Then open a calculator (or a physical one) and it gives the same number as Excel. So an hour after the fact you're arguing about floating point implementations to non-technical people :-) Regards! Esteban A. Maringolo
RO
Richard O'Keefe
Tue, Jun 15, 2021 1:36 AM

It's not quite clear what is happening in the other systems.
Here is R

6.7 + (32.8 - 35)

[1] 4.5

round(6.7 + (32.8 - 35))

[1] 4
The result is 4.499999.... but is printed as 4.5.

Here is Gambit Scheme

(+ 6.7 (- 32.8 35))

4.499999999999997

(round (+ 6.7 (- 32.8 35)))

Here is astc Smalltalk
6.7 + (32.8 - 35) printOn: Transcript
Transcript tab.
(6.7 + (32.8 - 35)) rounded printOn: Transcript.
Transcript cr.
4.499999999999997      4

And here is Python

x = 6.7 + (32.8 - 35)
x

4.499999999999997

round(x)

4

For what it's worth, I expected ScaledDecimal to act like fixed point
arithmetic, and implemented it that way in my own Smalltalk library, where
two ScaledDecimals do print the same if and only if they are numerically
exactly the same.  What Squeak and Pharo do is exceedingly odd: a ScaledDecimal
is an exact rational number (Integer or Fraction) combined with a precision that
is used for printing, not for calculation.

There really isn't any principle of least surprise when it comes to floating-
point arithmetic.  It's full of surprises and edge cases.  Excel in particular
is notorious for messing up due to trying to pretend all is well.

In this particular case, the exact result is 4.5
There are at least three rules for rounding such numbers: rounding out (5),
rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6).
So you are pushing up against an edge case for exact hand calculation!

I think you need to re-express your entire calculation to use exact arithmetic.
That or get agreement on "de minimis non curat lex".

On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo emaringolo@gmail.com wrote:

I'm coming back to this because I've been bitten by these floating
points things again.

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)

It will produce:
4.499999999999997

Which, when rounded, will produce 4.

In other places [2] I do the same simple addition and subtraction it
produces 4.5, that when rounded will produce 5.

I know now that Pharo doesn't lie to me while other systems do, and
all that Richard pointed to before.

The issue here is that I'm following some calculation formula that was
defined in some of the "other" systems, and so when I follow such a
formula I get these edgy cases where my system produces a different
output.

In this case the formula is for golf handicap calculations, and it
caused my system to give 4 instead of 5 to a player, resulting in
giving the first place to a player other than the one deserved.
It was no big deal (it's not The Masters), but these cases appear from
time to time.

Is there any way to "configure" the floating point calculation to
behave as the "other systems"?

What is the best way to anticipate these situations, am I the only one
being bitten by these issues?

Thanks in advance for any hints about these problems.

Best regards,

[1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo.
[2] VisualWorks, VAST, Excel, VB and all calculators I tried

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip> > The systems that print 7.1 are LYING to you, > and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

It's not quite clear what is happening in the other systems. Here is R > 6.7 + (32.8 - 35) [1] 4.5 > round(6.7 + (32.8 - 35)) [1] 4 The result *is* 4.499999.... but is *printed* as 4.5. Here is Gambit Scheme > (+ 6.7 (- 32.8 35)) 4.499999999999997 > (round (+ 6.7 (- 32.8 35))) 4. Here is astc Smalltalk 6.7 + (32.8 - 35) printOn: Transcript Transcript tab. (6.7 + (32.8 - 35)) rounded printOn: Transcript. Transcript cr. 4.499999999999997 4 And here is Python >>> x = 6.7 + (32.8 - 35) >>> x 4.499999999999997 >>> round(x) 4 For what it's worth, I expected ScaledDecimal to act like fixed point arithmetic, and implemented it that way in my own Smalltalk library, where two ScaledDecimals *do* print the same if and only if they are numerically exactly the same. What Squeak and Pharo do is exceedingly odd: a ScaledDecimal is an exact rational number (Integer or Fraction) combined with a precision that is used for printing, not for calculation. There really isn't any principle of least surprise when it comes to floating- point arithmetic. It's full of surprises and edge cases. Excel in particular is notorious for messing up due to trying to pretend all is well. In this particular case, the exact result is 4.5 There are at least three rules for rounding such numbers: rounding out (5), rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6). So you are pushing up against an edge case for exact hand calculation! I think you need to re-express your entire calculation to use exact arithmetic. That or get agreement on "de minimis non curat lex". On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo <emaringolo@gmail.com> wrote: > > I'm coming back to this because I've been bitten by these floating > points things again. > > If in Pharo [1] you do: > a := 6.7 + (32.8 - 35) > > It will produce: > 4.499999999999997 > > Which, when rounded, will produce 4. > > In other places [2] I do the same simple addition and subtraction it > produces 4.5, that when rounded will produce 5. > > I know now that Pharo doesn't lie to me while other systems do, and > all that Richard pointed to before. > > The issue here is that I'm following some calculation formula that was > defined in some of the "other" systems, and so when I follow such a > formula I get these edgy cases where my system produces a different > output. > > In this case the formula is for golf handicap calculations, and it > caused my system to give 4 instead of 5 to a player, resulting in > giving the first place to a player other than the one deserved. > It was no big deal (it's not The Masters), but these cases appear from > time to time. > > Is there any way to "configure" the floating point calculation to > behave as the "other systems"? > > What is the best way to anticipate these situations, am I the only one > being bitten by these issues? > > Thanks in advance for any hints about these problems. > > > Best regards, > > [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo. > [2] VisualWorks, VAST, Excel, VB and all calculators I tried > > > > Esteban A. Maringolo > > On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo <emaringolo@gmail.com> wrote: > > > > On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: > > > > > > "7.1 roundTo: 0.1 should return 7.1" > > > You're still not getting it. > > > > I was until Konrad explained it. > > > > > Binary floating point CANNOT represent either of those numbers. > > > You seem to be assuming that Pharo is making some mistake. > > > It isn't. All it is doing is refusing to lie to you. > > <snip> > > > The systems that print 7.1 are LYING to you, > > > and Pharo is not. > > > > I'm not assuming a mistake from Pharo, I had a wrong expectation what > > to get if I round to that precision. > > I don't know whether other systems lie or simply fulfill user > > expectations, if you send the #roundTo: to a float, I did expect to > > get a number with the same precision. > > That is my expectation as a user. As in the other thread I expected > > two scaled decimals that are printed equal to also be compared as > > equal (which they don't). > > > > Whether there is a good reason for those behaviors is beyond my > > current comprehension, but it certainly doesn't follow the "principle > > of least surprise". > > > > In any case, the method proposed by Tomohiro solved my issues. > > > > Regards, > > > > Esteban A. Maringolo
EM
Esteban Maringolo
Tue, Jun 15, 2021 2:23 AM

On Mon, Jun 14, 2021 at 10:37 PM Richard O'Keefe raoknz@gmail.com wrote:

For what it's worth, I expected ScaledDecimal to act like fixed point
arithmetic, and implemented it that way in my own Smalltalk library, where
two ScaledDecimals do print the same if and only if they are numerically
exactly the same.
What Squeak and Pharo do is exceedingly odd: a ScaledDecimal
is an exact rational number (Integer or Fraction) combined with a precision that
is used for printing, not for calculation.

I pointed out before the weird behavior of ScaledDecimals in Pharo,
two ScaledDecimal that print the same are not equal. Giving some weird
comparison issues as result.

There really isn't any principle of least surprise when it comes to floating-
point arithmetic.  It's full of surprises and edge cases.  Excel in particular
is notorious for messing up due to trying to pretend all is well.
In this particular case, the exact result is 4.5

Well... for the end user, it produces what they'd expect. So it might
mess up, but in a spreadsheet 6.7 - 2.2 should give 4.5.

There are at least three rules for rounding such numbers: rounding out (5),
rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6).
So you are pushing up against an edge case for exact hand calculation!

I implemented a Float>>#roundedHandicap method that does something
like the banking algorithm, but rounds positive numbers towards the
next integer and negative numbers towards zero.
E.g.
0.49 -> 0
0.5 -> 1
-0.5 -> 0
-0.51 -> -1

Nothing uses more than one decimal, so a ScaledDecimal would work but
the specification says that it should use all possible precision in
intermediate calculations, so I cannot use it.

I think you need to re-express your entire calculation to use exact arithmetic.

I really don't know how to do this, any pointers?

Nothing is more straightforward than addition and subtraction to me,
6.7 - 2.2 is the simplest it can get.

The common formula here is: h * s / 113 + (r - p), but in this
particular case s was 113 so it removed the "troubling" part.

That or get agreement on "de minimis non curat lex".

I had to search for that expression. Now I know, I agree.

Regards,

Esteban A. Maringolo

On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo emaringolo@gmail.com wrote:

I'm coming back to this because I've been bitten by these floating
points things again.

If in Pharo [1] you do:
a := 6.7 + (32.8 - 35)

It will produce:
4.499999999999997

Which, when rounded, will produce 4.

In other places [2] I do the same simple addition and subtraction it
produces 4.5, that when rounded will produce 5.

I know now that Pharo doesn't lie to me while other systems do, and
all that Richard pointed to before.

The issue here is that I'm following some calculation formula that was
defined in some of the "other" systems, and so when I follow such a
formula I get these edgy cases where my system produces a different
output.

In this case the formula is for golf handicap calculations, and it
caused my system to give 4 instead of 5 to a player, resulting in
giving the first place to a player other than the one deserved.
It was no big deal (it's not The Masters), but these cases appear from
time to time.

Is there any way to "configure" the floating point calculation to
behave as the "other systems"?

What is the best way to anticipate these situations, am I the only one
being bitten by these issues?

Thanks in advance for any hints about these problems.

Best regards,

[1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo.
[2] VisualWorks, VAST, Excel, VB and all calculators I tried

Esteban A. Maringolo

On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo emaringolo@gmail.com wrote:

On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe raoknz@gmail.com wrote:

"7.1 roundTo: 0.1 should return 7.1"
You're still not getting it.

I was until Konrad explained it.

Binary floating point CANNOT represent either of those numbers.
You seem to be assuming that Pharo is making some mistake.
It isn't.  All it is doing is refusing to lie to you.

<snip> > The systems that print 7.1 are LYING to you, > and Pharo is not.

I'm not assuming a mistake from Pharo, I had a wrong expectation what
to get if I round to that precision.
I don't know whether other systems lie or simply fulfill user
expectations, if you send the #roundTo: to a float, I did expect to
get a number with the same precision.
That is my expectation as a user. As in the other thread I expected
two scaled decimals that are printed equal to also be compared as
equal  (which they don't).

Whether there is a good reason for those behaviors is beyond my
current comprehension, but it certainly doesn't follow the "principle
of least surprise".

In any case, the method proposed by Tomohiro solved my issues.

Regards,

Esteban A. Maringolo

On Mon, Jun 14, 2021 at 10:37 PM Richard O'Keefe <raoknz@gmail.com> wrote: > For what it's worth, I expected ScaledDecimal to act like fixed point > arithmetic, and implemented it that way in my own Smalltalk library, where > two ScaledDecimals *do* print the same if and only if they are numerically > exactly the same. > What Squeak and Pharo do is exceedingly odd: a ScaledDecimal > is an exact rational number (Integer or Fraction) combined with a precision that > is used for printing, not for calculation. I pointed out before the weird behavior of ScaledDecimals in Pharo, two ScaledDecimal that print the same are not equal. Giving some weird comparison issues as result. > There really isn't any principle of least surprise when it comes to floating- > point arithmetic. It's full of surprises and edge cases. Excel in particular > is notorious for messing up due to trying to pretend all is well. > In this particular case, the exact result is 4.5 Well... for the end user, it produces what they'd expect. So it might mess up, but in a spreadsheet 6.7 - 2.2 should give 4.5. > There are at least three rules for rounding such numbers: rounding out (5), > rounding in (4), and rounding in [banker'salgorithm] (4 here, but 5.5 -> 6). > So you are pushing up against an edge case for exact hand calculation! I implemented a Float>>#roundedHandicap method that does something like the banking algorithm, but rounds positive numbers towards the next integer and negative numbers towards zero. E.g. 0.49 -> 0 0.5 -> 1 -0.5 -> 0 -0.51 -> -1 Nothing uses more than one decimal, so a ScaledDecimal would work but the specification says that it should use all possible precision in intermediate calculations, so I cannot use it. > I think you need to re-express your entire calculation to use exact arithmetic. I really don't know how to do this, any pointers? Nothing is more straightforward than addition and subtraction to me, 6.7 - 2.2 is the simplest it can get. The common formula here is: h * s / 113 + (r - p), but in this particular case s was 113 so it removed the "troubling" part. > That or get agreement on "de minimis non curat lex". I had to search for that expression. Now I know, I agree. Regards, Esteban A. Maringolo > > > On Tue, 15 Jun 2021 at 08:45, Esteban Maringolo <emaringolo@gmail.com> wrote: > > > > I'm coming back to this because I've been bitten by these floating > > points things again. > > > > If in Pharo [1] you do: > > a := 6.7 + (32.8 - 35) > > > > It will produce: > > 4.499999999999997 > > > > Which, when rounded, will produce 4. > > > > In other places [2] I do the same simple addition and subtraction it > > produces 4.5, that when rounded will produce 5. > > > > I know now that Pharo doesn't lie to me while other systems do, and > > all that Richard pointed to before. > > > > The issue here is that I'm following some calculation formula that was > > defined in some of the "other" systems, and so when I follow such a > > formula I get these edgy cases where my system produces a different > > output. > > > > In this case the formula is for golf handicap calculations, and it > > caused my system to give 4 instead of 5 to a player, resulting in > > giving the first place to a player other than the one deserved. > > It was no big deal (it's not The Masters), but these cases appear from > > time to time. > > > > Is there any way to "configure" the floating point calculation to > > behave as the "other systems"? > > > > What is the best way to anticipate these situations, am I the only one > > being bitten by these issues? > > > > Thanks in advance for any hints about these problems. > > > > > > Best regards, > > > > [1] Dolphin Smalltalk, JS, Python, Ruby, Dart produces the same output as Pharo. > > [2] VisualWorks, VAST, Excel, VB and all calculators I tried > > > > > > > > Esteban A. Maringolo > > > > On Tue, Sep 8, 2020 at 12:45 AM Esteban Maringolo <emaringolo@gmail.com> wrote: > > > > > > On Tue, Sep 8, 2020 at 12:16 AM Richard O'Keefe <raoknz@gmail.com> wrote: > > > > > > > > "7.1 roundTo: 0.1 should return 7.1" > > > > You're still not getting it. > > > > > > I was until Konrad explained it. > > > > > > > Binary floating point CANNOT represent either of those numbers. > > > > You seem to be assuming that Pharo is making some mistake. > > > > It isn't. All it is doing is refusing to lie to you. > > > <snip> > > > > The systems that print 7.1 are LYING to you, > > > > and Pharo is not. > > > > > > I'm not assuming a mistake from Pharo, I had a wrong expectation what > > > to get if I round to that precision. > > > I don't know whether other systems lie or simply fulfill user > > > expectations, if you send the #roundTo: to a float, I did expect to > > > get a number with the same precision. > > > That is my expectation as a user. As in the other thread I expected > > > two scaled decimals that are printed equal to also be compared as > > > equal (which they don't). > > > > > > Whether there is a good reason for those behaviors is beyond my > > > current comprehension, but it certainly doesn't follow the "principle > > > of least surprise". > > > > > > In any case, the method proposed by Tomohiro solved my issues. > > > > > > Regards, > > > > > > Esteban A. Maringolo
KH
Konrad Hinsen
Tue, Jun 15, 2021 5:02 AM

On 15/06/2021 01:03, Esteban Maringolo wrote:

Sure, but what initiated this thread was a reference to roundTo: 0.1
which produced a "wrong" output.

(9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005"
7.1 roundTo: 0.1 "=> 7.1000000000000005"

However, at this point I know that Pharo "does the right, raw, thing"
(at least compared to other mainstream languages), but it still
produces a surprise effect.

That's the "floating point surprise" that everyone has at some point, no
matter the language and runtime system. If that surprise is a problem
for you, are you sure that floating-point arithmetic is what you really
want? Maybe your needs are better served with integers and fractions.

Konrad.

On 15/06/2021 01:03, Esteban Maringolo wrote: > Sure, but what initiated this thread was a reference to roundTo: 0.1 > which produced a "wrong" output. > > (9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005" > 7.1 roundTo: 0.1 "=> 7.1000000000000005" > > However, at this point I know that Pharo "does the right, raw, thing" > (at least compared to other mainstream languages), but it still > produces a surprise effect. That's the "floating point surprise" that everyone has at some point, no matter the language and runtime system. If that surprise is a problem for you, are you sure that floating-point arithmetic is what you really want? Maybe your needs are better served with integers and fractions. Konrad.
SM
Steffen Märcker
Tue, Jun 15, 2021 6:47 AM

Have you considered using fixed-point arithmetic? For example:
7.1s2 roundTo: 0.1s2

The rule of thumb I stick to is to use FP only if I know the inaccuracies
won't bite me. Funny enough, both 7.1 and 0.1 are already not accurately
representable as floats. (And by coincidence, I prepared exam questions
about floats for my students yesterday. )

Kind regards,
Steffen

Konrad Hinsen schrieb am Dienstag, 15. Juni 2021 07:02:30 (+02:00):

On 15/06/2021 01:03, Esteban Maringolo wrote:

Sure, but what initiated this thread was a reference to roundTo: 0.1
which produced a "wrong" output.

(9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005"
7.1 roundTo: 0.1 "=> 7.1000000000000005"

However, at this point I know that Pharo "does the right, raw, thing"
(at least compared to other mainstream languages), but it still
produces a surprise effect.

That's the "floating point surprise" that everyone has at some point, no

matter the language and runtime system. If that surprise is a problem for
you, are you sure that floating-point arithmetic is what you really want?
Maybe your needs are better served with integers and fractions.

Konrad.

--
Gesendet mit Vivaldi Mail. Laden Sie Vivaldi kostenlos von vivaldi.com
herunter.

Have you considered using fixed-point arithmetic? For example: 7.1s2 roundTo: 0.1s2 The rule of thumb I stick to is to use FP only if I know the inaccuracies won't bite me. Funny enough, both 7.1 and 0.1 are already not accurately representable as floats. (And by coincidence, I prepared exam questions about floats for my students yesterday. ) Kind regards, Steffen Konrad Hinsen schrieb am Dienstag, 15. Juni 2021 07:02:30 (+02:00): > On 15/06/2021 01:03, Esteban Maringolo wrote: > > Sure, but what initiated this thread was a reference to roundTo: 0.1 > > which produced a "wrong" output. > > > > (9.1 + (-2.0)) roundTo: 0.1 "=> 7.1000000000000005" > > 7.1 roundTo: 0.1 "=> 7.1000000000000005" > > > > However, at this point I know that Pharo "does the right, raw, thing" > > (at least compared to other mainstream languages), but it still > > produces a surprise effect. > > That's the "floating point surprise" that everyone has at some point, no matter the language and runtime system. If that surprise is a problem for you, are you sure that floating-point arithmetic is what you really want? Maybe your needs are better served with integers and fractions. > > > Konrad. > > -- Gesendet mit Vivaldi Mail. Laden Sie Vivaldi kostenlos von vivaldi.com herunter.