Floating point arithmetic

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Floating point arithmetic

Donald Howard
Hello everyone,

This is an issue I've had awareness of going way back but it's the first time I've had to personally deal with it.  I've done some research and found it addressed in a number of ways but given current time pressures and a huge list of to-dos, I thought I'd turn to the community for rapid advice to get me over the hump.  The circumstances are summarized below in code and comments suitable for a playground.

"This is the actual arithmetic I want to do...
 0.09560268 - 0.005 = 0.09060268"

"Evaluate this in a playground and you'll see this is what
 floating point arithmetic produces --the first two are wrong, every one after is correct"
0.09560268 - 0.005 "=> 0.09060267999999999".
0.0956026 - 0.005  "=> 0.09060259999999999".
0.095602 - 0.005   "=> 0.090602".
0.09560 - 0.005    "=> 0.0906".
0.0956 - 0.005     "=> 0.0906".
0.095 - 0.005      "=> 0.09".

"This workaround works"
0.09560268 - 0.005 roundTo: 0.00000001 "=> 0.09060268".
"but one has to compute number of digits of precision
and according to study above, it's not necessary at
precisions >= 0.000001"

"What are other suggestions, workarounds or approaches community has?"
"THANKS!"


Don Howard

Founding Member
+31653139744
(US) 651-253-7024
Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Paul DeBruicker
Whats wrong with #roundedTo: ?


If you actually need it calculated to 8 significant digits then you can use
scaled decimals e.g.

(0.09560268 asScaledDecimal - 0.005 asScaledDecimal)

see  https://0.30000000000000004.com for more about why floating point math
does this sometimes





Donald Howard wrote

> Hello everyone,
>
> This is an issue I've had awareness of going way back but it's the first
> time I've had to personally deal with it.  I've done some research and
> found it addressed in a number of ways but given current time pressures
> and
> a huge list of to-dos, I thought I'd turn to the community for rapid
> advice
> to get me over the hump.  The circumstances are summarized below in code
> and comments suitable for a playground.
>
> "This is the actual arithmetic I want to do...
>  0.09560268 - 0.005 = 0.09060268"
>
> "Evaluate this in a playground and you'll see this is what
>  floating point arithmetic produces --the first two are wrong, every one
> after is correct"
> 0.09560268 - 0.005 "=> 0.09060267999999999".
> 0.0956026 - 0.005  "=> 0.09060259999999999".
> 0.095602 - 0.005   "=> 0.090602".
> 0.09560 - 0.005    "=> 0.0906".
> 0.0956 - 0.005     "=> 0.0906".
> 0.095 - 0.005      "=> 0.09".
>
> "This workaround works"
> 0.09560268 - 0.005 roundTo: 0.00000001 "=> 0.09060268".
> "but one has to compute number of digits of precision
> and according to study above, it's not necessary at
> precisions >= 0.000001"
>
> "What are other suggestions, workarounds or approaches community has?"
> "THANKS!"
>
>
> Don Howard
>
> <https://objectguild.com>
> *Founding Member*

> dhoward@

> +31653139744
> (US) 651-253-7024





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

khinsen
In reply to this post by Donald Howard
On 12/01/2020 21:13, Donald Howard wrote:
> "Evaluate this in a playground and you'll see this is what
>  floating point arithmetic produces --the first two are wrong, every
> one after is correct"
> 0.09560268 - 0.005 "=> 0.09060267999999999".
> 0.0956026 - 0.005  "=> 0.09060259999999999".
> 0.095602 - 0.005   "=> 0.090602".

Wrong in what sense? I am rather sure that the computation is done
correctly, meaning that it follows the rules defined by IEEE standard
754. I am also relatively sure (meaning a bit less) that the conversion
of the binary result to a decimal output string is correct, in the sense
that it applies today's preferred practice of ensuring round-trip
equality. So you probably mean that the result is no what you expected.

The main point to be clear about is if you care about the binary value
or about its decimal representation as a string. If you need the
internal value to be exact, you have to switch to something other than
binary floats - scaled decimals might work for you. If you only want
nice-looking outputs, you can probably get what you want using roundTo:
applied to the result.


Cheers,

Konrad.



Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Richard O'Keefe
In reply to this post by Donald Howard
You say that the first two results are wrong.
No.  The first two results are *exactly* what they are supposed to be.
Floating point arithmetic is NOT mathematical real arithmetic.
The floating point *numbers* are exact rational numbers of the form
n * 2^k where n is a (bounded) integer and k is a (bounded) integer.
If you enter a number that is not of this form (and within bounds)
you will get a *different* number that *is* of that form and is close.
The floating point *operations* in IEEE arithmetic are exact
when and only when the result is a number of that form (and within
bounds), otherwise the result is *approximate*.

If you want exact arithmetic on numbers of the form n * 10^k,
ANSI Smalltalk provides the ScaledDecimal class, which, sigh,
Squeak and Pharo interpret as "rational number *printed* in
decimal form but not *computed* using decimal arithmetic", so
that can give extremely confusing results too.

So what you are going to have to do is use rational numbers,
which are in Smalltalk the union of Integer and Fraction.


On Mon, 13 Jan 2020 at 09:13, Donald Howard <[hidden email]> wrote:
Hello everyone,

This is an issue I've had awareness of going way back but it's the first time I've had to personally deal with it.  I've done some research and found it addressed in a number of ways but given current time pressures and a huge list of to-dos, I thought I'd turn to the community for rapid advice to get me over the hump.  The circumstances are summarized below in code and comments suitable for a playground.

"This is the actual arithmetic I want to do...
 0.09560268 - 0.005 = 0.09060268"

"Evaluate this in a playground and you'll see this is what
 floating point arithmetic produces --the first two are wrong, every one after is correct"
0.09560268 - 0.005 "=> 0.09060267999999999".
0.0956026 - 0.005  "=> 0.09060259999999999".
0.095602 - 0.005   "=> 0.090602".
0.09560 - 0.005    "=> 0.0906".
0.0956 - 0.005     "=> 0.0906".
0.095 - 0.005      "=> 0.09".

"This workaround works"
0.09560268 - 0.005 roundTo: 0.00000001 "=> 0.09060268".
"but one has to compute number of digits of precision
and according to study above, it's not necessary at
precisions >= 0.000001"

"What are other suggestions, workarounds or approaches community has?"
"THANKS!"


Don Howard

Founding Member
+31653139744
(US) 651-253-7024
Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Ben Coman


On Mon, 13 Jan 2020 at 19:42, Richard O'Keefe <[hidden email]> wrote:
You say that the first two results are wrong.
No.  The first two results are *exactly* what they are supposed to be.
Floating point arithmetic is NOT mathematical real arithmetic.
The floating point *numbers* are exact rational numbers of the form
n * 2^k where n is a (bounded) integer and k is a (bounded) integer.
If you enter a number that is not of this form (and within bounds)
you will get a *different* number that *is* of that form and is close.
The floating point *operations* in IEEE arithmetic are exact
when and only when the result is a number of that form (and within
bounds), otherwise the result is *approximate*.

If you want exact arithmetic on numbers of the form n * 10^k,
ANSI Smalltalk provides the ScaledDecimal class, which, sigh,

How could this be improved?

 
Squeak and Pharo interpret as "rational number *printed* in
decimal form but not *computed* using decimal arithmetic"

I'm interested to understand what is the benefit of doing it this way. 
Anyone know history of it?

cheers -ben

, so
that can give extremely confusing results too.

So what you are going to have to do is use rational numbers,
which are in Smalltalk the union of Integer and Fraction.


On Mon, 13 Jan 2020 at 09:13, Donald Howard <[hidden email]> wrote:
Hello everyone,

This is an issue I've had awareness of going way back but it's the first time I've had to personally deal with it.  I've done some research and found it addressed in a number of ways but given current time pressures and a huge list of to-dos, I thought I'd turn to the community for rapid advice to get me over the hump.  The circumstances are summarized below in code and comments suitable for a playground.

"This is the actual arithmetic I want to do...
 0.09560268 - 0.005 = 0.09060268"

"Evaluate this in a playground and you'll see this is what
 floating point arithmetic produces --the first two are wrong, every one after is correct"
0.09560268 - 0.005 "=> 0.09060267999999999".
0.0956026 - 0.005  "=> 0.09060259999999999".
0.095602 - 0.005   "=> 0.090602".
0.09560 - 0.005    "=> 0.0906".
0.0956 - 0.005     "=> 0.0906".
0.095 - 0.005      "=> 0.09".

"This workaround works"
0.09560268 - 0.005 roundTo: 0.00000001 "=> 0.09060268".
"but one has to compute number of digits of precision
and according to study above, it's not necessary at
precisions >= 0.000001"

"What are other suggestions, workarounds or approaches community has?"
"THANKS!"


Don Howard

Founding Member
+31653139744
(US) 651-253-7024
Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Sven Van Caekenberghe-2
In reply to this post by Paul DeBruicker


> On 13 Jan 2020, at 00:28, Paul DeBruicker <[hidden email]> wrote:
>
> Whats wrong with #roundedTo: ?
>
>
> If you actually need it calculated to 8 significant digits then you can use
> scaled decimals e.g.
>
> (0.09560268 asScaledDecimal - 0.005 asScaledDecimal)

The weird thing is though, that is still does not behave 100% as one would expect (i.e. it does not seem exact).

0.09560268 asScaledDecimal - 0.005 asScaledDecimal. "0.09060268s8"

0.09560268 asScaledDecimal - 0.005 asScaledDecimal = 0.09060268 asScaledDecimal. "false"

0.09560268 asScaledDecimal - 0.005 asScaledDecimal = 0.09060268s8. "false"

The internal fractions are not the same ...

While

(9560268 / 1e8) - (5 / 1e3) = (9060268 / 1e8). "true"

So, is the equality test of ScaledDecimal correct ?

> see  https://0.30000000000000004.com for more about why floating point math
> does this sometimes
>
>
>
>
>
> Donald Howard wrote
>> Hello everyone,
>>
>> This is an issue I've had awareness of going way back but it's the first
>> time I've had to personally deal with it.  I've done some research and
>> found it addressed in a number of ways but given current time pressures
>> and
>> a huge list of to-dos, I thought I'd turn to the community for rapid
>> advice
>> to get me over the hump.  The circumstances are summarized below in code
>> and comments suitable for a playground.
>>
>> "This is the actual arithmetic I want to do...
>> 0.09560268 - 0.005 = 0.09060268"
>>
>> "Evaluate this in a playground and you'll see this is what
>> floating point arithmetic produces --the first two are wrong, every one
>> after is correct"
>> 0.09560268 - 0.005 "=> 0.09060267999999999".
>> 0.0956026 - 0.005  "=> 0.09060259999999999".
>> 0.095602 - 0.005   "=> 0.090602".
>> 0.09560 - 0.005    "=> 0.0906".
>> 0.0956 - 0.005     "=> 0.0906".
>> 0.095 - 0.005      "=> 0.09".
>>
>> "This workaround works"
>> 0.09560268 - 0.005 roundTo: 0.00000001 "=> 0.09060268".
>> "but one has to compute number of digits of precision
>> and according to study above, it's not necessary at
>> precisions >= 0.000001"
>>
>> "What are other suggestions, workarounds or approaches community has?"
>> "THANKS!"
>>
>>
>> Don Howard
>>
>> &lt;https://objectguild.com&gt;
>> *Founding Member*
>
>> dhoward@
>
>> +31653139744
>> (US) 651-253-7024
>
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html


Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

wernerk
Hi Sven,

if you dont transform floats, that are not always exactly what they seem
to be, you get what you would expect:
0.09560268s8 - 0.005s8 = 0.09060268s8. "true"
"of course"
a:=0.09560268 asScaledDecimal.
0.09560268s8=a . "false"
"you could eg do this:"
b:=a roundTo: 0.00000001s8.
"then"
0.09560268s8=b . "true"

but if you do something like this generally in Float>>asScaledDecimal
you could loose some precision that could be unwanted in some other
circumstances (or perhaps not).

werner

On 1/13/20 2:13 PM, Sven Van Caekenberghe wrote:
> 0.09560268 asScaledDecimal - 0.005 asScaledDecimal = 0.09060268s8. "false"

Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Sven Van Caekenberghe-2
Ah, yes, yes, sending #asScaledDecimal to a Float is too late, the precision is already lost. It makes total sense now.

Thank you, Werner, for the explanation.

> On 13 Jan 2020, at 16:13, werner kassens <[hidden email]> wrote:
>
> Hi Sven,
>
> if you dont transform floats, that are not always exactly what they seem
> to be, you get what you would expect:
> 0.09560268s8 - 0.005s8 = 0.09060268s8. "true"
> "of course"
> a:=0.09560268 asScaledDecimal.
> 0.09560268s8=a . "false"
> "you could eg do this:"
> b:=a roundTo: 0.00000001s8.
> "then"
> 0.09560268s8=b . "true"
>
> but if you do something like this generally in Float>>asScaledDecimal
> you could loose some precision that could be unwanted in some other
> circumstances (or perhaps not).
>
> werner
>
> On 1/13/20 2:13 PM, Sven Van Caekenberghe wrote:
>> 0.09560268 asScaledDecimal - 0.005 asScaledDecimal = 0.09060268s8. "false"
>


Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Pierce Ng-3
In reply to this post by Donald Howard
On Sun, Jan 12, 2020 at 02:13:00PM -0600, Donald Howard wrote:
> "What are other suggestions, workarounds or approaches community has?"

This is a good read on the subject:

  https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Title is "What every computer scientist should know about floating point arithmetic".

Pierce

Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Pierce Ng-3
In reply to this post by Richard O'Keefe
On Tue, Jan 14, 2020 at 12:41:51AM +1300, Richard O'Keefe wrote:
> Squeak and Pharo interpret as "rational number *printed* in
> decimal form but not *computed* using decimal arithmetic", so
> that can give extremely confusing results too.

Can you expand on this please?

For money-related calculations I have been using Hernán Morales Durand's
FixedDecimal: https://github.com/hernanmd/FixedDecimal.

Pierce


Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Bruce O'Neel-2
In reply to this post by Pierce Ng-3
HI,

I would upgrade that "a good read" to a critical read if you do anything with floating point.  Floating point numbers are not real numbers but rather a small subset, and, have all kinds of funny properties. But we use them just like real numbers and that's what catches us out.

cheers

bruce



14 January 2020 03:05 Pierce Ng <[hidden email]> wrote:
On Sun, Jan 12, 2020 at 02:13:00PM -0600, Donald Howard wrote:
> "What are other suggestions, workarounds or approaches community has?"

This is a good read on the subject:

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Title is "What every computer scientist should know about floating point arithmetic".

Pierce


Reply | Threaded
Open this post in threaded view
|

Re: Floating point arithmetic

Donald Howard
Thanks, everyone, for the great input.  I will continue to work thru the background readings and recommendations you graciously supplied and go from there.

Best regards,
- Don

On Tue, 14 Jan 2020 at 07:04, Bruce O'Neel <[hidden email]> wrote:
HI,

I would upgrade that "a good read" to a critical read if you do anything with floating point.  Floating point numbers are not real numbers but rather a small subset, and, have all kinds of funny properties. But we use them just like real numbers and that's what catches us out.

cheers

bruce



14 January 2020 03:05 Pierce Ng <[hidden email]> wrote:
On Sun, Jan 12, 2020 at 02:13:00PM -0600, Donald Howard wrote:
> "What are other suggestions, workarounds or approaches community has?"

This is a good read on the subject:


Title is "What every computer scientist should know about floating point arithmetic".

Pierce