roundTo: strange behavior

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

roundTo: strange behavior

stepharo
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
  "12.200000000000001"

12.222222222222221 roundTo: 0.01
  "12.22"


Stef


Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Thierry Goubier
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry

2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef



Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

kilon.alios
I think lisp solves this problem by using integers for its floats , or something along those line, I remember reading about it somewhere when I was studying common lisp 5 years ago

Or maybe my memory fails me

On Sun, Oct 23, 2016 at 7:24 PM Thierry Goubier <[hidden email]> wrote:
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry


2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef



Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

stepharo
In reply to this post by Thierry Goubier

I see.

I writing a little example for my new newbies book

now how can get only two digits after the .


Stef


Le 23/10/16 à 18:23, Thierry Goubier a écrit :
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry

2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef




Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

stepharo

3.1479 roundUpTo: 0.01 is what I was looking for.


Stef



Le 23/10/16 à 18:35, stepharo a écrit :

I see.

I writing a little example for my new newbies book

now how can get only two digits after the .


Stef


Le 23/10/16 à 18:23, Thierry Goubier a écrit :
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry

2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef





Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

kilon.alios
In reply to this post by kilon.alios
aaaaaand I was wrong, my bad

On Sun, Oct 23, 2016 at 7:29 PM Dimitris Chloupis <[hidden email]> wrote:
I think lisp solves this problem by using integers for its floats , or something along those line, I remember reading about it somewhere when I was studying common lisp 5 years ago

Or maybe my memory fails me

On Sun, Oct 23, 2016 at 7:24 PM Thierry Goubier <[hidden email]> wrote:
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry


2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef



Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Peter Uhnak
In reply to this post by stepharo
I usually use 12.222222222222221 round: 2 "12.22".

Peter

On Sun, Oct 23, 2016 at 06:38:47PM +0200, stepharo wrote:

> 3.1479 roundUpTo: 0.01 is what I was looking for.
>
>
> Stef
>
>
>
> Le 23/10/16 à 18:35, stepharo a écrit :
> >
> >I see.
> >
> >I writing a little example for my new newbies book
> >
> >now how can get only two digits after the .
> >
> >
> >Stef
> >
> >
> >Le 23/10/16 à 18:23, Thierry Goubier a écrit :
> >>I think that's called 'welcome to the wonderfull world of
> >>floating points approximations' and not a bug :(
> >>
> >>See unums/Gustafson for something more interesting on the subject.
> >>
> >>Thierry
> >>
> >>2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]
> >><mailto:[hidden email]>>:
> >>
> >>    Hi
> >>
> >>    I'm wondering if we do not have a bug here
> >>
> >>    12.222222222222221 roundTo: 0.1
> >>     "12.200000000000001"
> >>
> >>    12.222222222222221 roundTo: 0.01
> >>     "12.22"
> >>
> >>
> >>    Stef
> >>
> >>
> >>
> >
>

Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

stepharo
Thanks because roundUpTo: did not make it either :)


Le 23/10/16 à 18:45, Peter Uhnak a écrit :

> I usually use 12.222222222222221 round: 2 "12.22".
>
> Peter
>
> On Sun, Oct 23, 2016 at 06:38:47PM +0200, stepharo wrote:
>> 3.1479 roundUpTo: 0.01 is what I was looking for.
>>
>>
>> Stef
>>
>>
>>
>> Le 23/10/16 à 18:35, stepharo a écrit :
>>> I see.
>>>
>>> I writing a little example for my new newbies book
>>>
>>> now how can get only two digits after the .
>>>
>>>
>>> Stef
>>>
>>>
>>> Le 23/10/16 à 18:23, Thierry Goubier a écrit :
>>>> I think that's called 'welcome to the wonderfull world of
>>>> floating points approximations' and not a bug :(
>>>>
>>>> See unums/Gustafson for something more interesting on the subject.
>>>>
>>>> Thierry
>>>>
>>>> 2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]
>>>> <mailto:[hidden email]>>:
>>>>
>>>>     Hi
>>>>
>>>>     I'm wondering if we do not have a bug here
>>>>
>>>>     12.222222222222221 roundTo: 0.1
>>>>      "12.200000000000001"
>>>>
>>>>     12.222222222222221 roundTo: 0.01
>>>>      "12.22"
>>>>
>>>>
>>>>     Stef
>>>>
>>>>
>>>>
>


Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

philippeback
In reply to this post by stepharo
I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil

On Sun, Oct 23, 2016 at 6:35 PM, stepharo <[hidden email]> wrote:

I see.

I writing a little example for my new newbies book

now how can get only two digits after the .


Stef


Le 23/10/16 à 18:23, Thierry Goubier a écrit :
I think that's called 'welcome to the wonderfull world of floating points approximations' and not a bug :(

See unums/Gustafson for something more interesting on the subject.

Thierry

2016-10-23 18:16 GMT+02:00 stepharo <[hidden email]>:
Hi

I'm wondering if we do not have a bug here

12.222222222222221 roundTo: 0.1
 "12.200000000000001"

12.222222222222221 roundTo: 0.01
 "12.22"


Stef





Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Henrik Sperre Johansen
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Sven Van Caekenberghe-2

> On 25 Oct 2016, at 11:05, Henrik Johansen <[hidden email]> wrote:
>
> +1.
>
> Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
> As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.
>
> Cheers,
> Henry
>
> * And in that case, you'd use ScaledDecimals

YES !!

So true.

>> On 23 Oct 2016, at 7:08 , [hidden email] wrote:
>>
>> I use the Printf package for that.
>>
>> v := 65.456.
>> 'With 2 decimal digits: %5.2f, or 3 like this: %6.3f'
>> printf: {v. v}.
>>
>> With 2 decimal digits: 65.45, or 3 like this: 65.456
>>
>> It is in http://www.smalltalkhub.com/#!/~philippeback/HOExtras
>>
>> Printf
>>
>> I am just used to C printf and well, I like the way it works.
>>
>> Phil


Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

stepharo
In reply to this post by Henrik Sperre Johansen

Ok for the advice

Now round: aNumberOfDigits seems to work fine.

Stef


Le 25/10/16 à 11:05, Henrik Johansen a écrit :
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil

Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Nicolas Cellier


2016-10-25 23:22 GMT+02:00 stepharo <[hidden email]>:

Ok for the advice

Now round: aNumberOfDigits seems to work fine.

Stef



I hate to say that, but try in python, they got it right...

 
Le 25/10/16 à 11:05, Henrik Johansen a écrit :
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil


Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

stepharo
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.

You see I'm not good in math so even if I try hard I will not have a good solution.
This is the same for marcus and most people in our team.
I reopened these issues.

Stef


2016-10-25 23:22 GMT+02:00 stepharo <[hidden email]>:

Ok for the advice

Now round: aNumberOfDigits seems to work fine.

Stef



I hate to say that, but try in python, they got it right...

 
Le 25/10/16 à 11:05, Henrik Johansen a écrit :
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil



Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Nicolas Cellier


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...


You see I'm not good in math so even if I try hard I will not have a good solution.
This is the same for marcus and most people in our team.
I reopened these issues.

Stef



2016-10-25 23:22 GMT+02:00 stepharo <[hidden email]>:

Ok for the advice

Now round: aNumberOfDigits seems to work fine.

Stef



I hate to say that, but try in python, they got it right...

 
Le 25/10/16 à 11:05, Henrik Johansen a écrit :
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil




Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Clément Béra
I think the right way to solve these issues is not to think about it like a Math problem.

We need to write tests showing bugs and doing lots of coverage.

Then, we can look into other programming languages (Java, Ruby, Python, etc), port an implementation and ensure it's correct.

This is the kind of things where people have spent days to get right and efficient. The goal is not to figure how to do it better but how to port the best implementation out there.

On Wed, Oct 26, 2016 at 9:58 AM, Nicolas Cellier <[hidden email]> wrote:


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...


You see I'm not good in math so even if I try hard I will not have a good solution.
This is the same for marcus and most people in our team.
I reopened these issues.

Stef



2016-10-25 23:22 GMT+02:00 stepharo <[hidden email]>:

Ok for the advice

Now round: aNumberOfDigits seems to work fine.

Stef



I hate to say that, but try in python, they got it right...

 
Le 25/10/16 à 11:05, Henrik Johansen a écrit :
+1.

Unless you're dealing with fixed precision* entities, it's usually better to specify digits to display in printing methods themselves (#printShowingDecimalPlaces: & friends in base image).
As per previous discussions around this that arise every second year or so, rounding the number itself (as long as we're dealing with floats) will never work as you want reliably.

Cheers,
Henry

* And in that case, you'd use ScaledDecimals 

On 23 Oct 2016, at 7:08 , [hidden email] wrote:

I use the Printf package for that.

v := 65.456.
'With 2 decimal digits: %5.2f, or 3 like this: %6.3f' 
printf: {v. v}.

With 2 decimal digits: 65.45, or 3 like this: 65.456


Printf

I am just used to C printf and well, I like the way it works.

Phil





Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

wernerk
In reply to this post by Nicolas Cellier
Hi Nicolas,
regarding rounding Fractions:
i use fractions if i want to get an exact result (eg for comparing the result with Float calculations). if #round: returns a Float all further calcs (with Fractions) will get contaminated, since the rest will become Floats too. Hence the "asScaledDecimal: numberOfWishedDecimal" seems better to me, but i wonder why these transformations at the end are necessary at all? just for the looks? i'd suppose every person, who knows how to use Fractions, also knows how to append a #asScaledDecimal: to a result by himself, should he want that.

taking as an example financial calcs that first use 2 decimals. occasionaly the final result will be basepoints, often small ones like 0.003. with scaledDecimals the result would be (ok, look like) 0 since scaledDecimals also contaminate the calc. of course one could correct this simply with an #asScaledDecimal:3 at the end. nevertheless a first look at the zero result would surprise me for a tenth of a second.
werner

On 10/26/2016 09:58 AM, Nicolas Cellier wrote:


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...

Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Nicolas Cellier


2016-10-26 13:11 GMT+02:00 test <[hidden email]>:
Hi Nicolas,
regarding rounding Fractions:
i use fractions if i want to get an exact result (eg for comparing the result with Float calculations). if #round: returns a Float all further calcs (with Fractions) will get contaminated, since the rest will become Floats too. Hence the "asScaledDecimal: numberOfWishedDecimal" seems better to me, but i wonder why these transformations at the end are necessary at all? just for the looks? i'd suppose every person, who knows how to use Fractions, also knows how to append a #asScaledDecimal: to a result by himself, should he want that.

taking as an example financial calcs that first use 2 decimals. occasionaly the final result will be basepoints, often small ones like 0.003. with scaledDecimals the result would be (ok, look like) 0 since scaledDecimals also contaminate the calc. of course one could correct this simply with an #asScaledDecimal:3 at the end. nevertheless a first look at the zero result would surprise me for a tenth of a second.
werner


Hi Werner,
I don't know the purpose of round: at all.
Most often this kind of message was used before printing probably because lack of versatile formatted print messages.
In Squeak I replaced most usages of roundTo: by printShowing(Max)DecimalPlaces:.
Now if it has been added in Pharo and other languages, there must be some use cases I presume.
Maybe the analysis could be carried on these use cases?

Beware, converting a Fraction asScaledDecimal will NOT round.
Only the printString is rounded, but the number keeps its whole precision.
Example (1/3 asScaledDecimal: 1)*3 = 1.0s, not 0.9s.

ScaledDecimals as they are now are just Fraction with a different printString...
Not very much added value.

Nicolas
 
On 10/26/2016 09:58 AM, Nicolas Cellier wrote:


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...


Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

wernerk
Hi Nicolas,
yes, i know. suppose you calc some financial thing and one intermediate result will be in $. you have to round this Fraction-result  to 2 decimals. now you use this to further calc basepoints as the final result. you have to convert this to 3 decimals. looking at this final result with 2 decimals can be be irritating for a moment, if you debug the calcs. and <g> btw i never use scaledDecimals.
werner

On 10/26/2016 02:06 PM, Nicolas Cellier wrote:


2016-10-26 13:11 GMT+02:00 test <[hidden email]>:
Hi Nicolas,
regarding rounding Fractions:
i use fractions if i want to get an exact result (eg for comparing the result with Float calculations). if #round: returns a Float all further calcs (with Fractions) will get contaminated, since the rest will become Floats too. Hence the "asScaledDecimal: numberOfWishedDecimal" seems better to me, but i wonder why these transformations at the end are necessary at all? just for the looks? i'd suppose every person, who knows how to use Fractions, also knows how to append a #asScaledDecimal: to a result by himself, should he want that.

taking as an example financial calcs that first use 2 decimals. occasionaly the final result will be basepoints, often small ones like 0.003. with scaledDecimals the result would be (ok, look like) 0 since scaledDecimals also contaminate the calc. of course one could correct this simply with an #asScaledDecimal:3 at the end. nevertheless a first look at the zero result would surprise me for a tenth of a second.
werner


Hi Werner,
I don't know the purpose of round: at all.
Most often this kind of message was used before printing probably because lack of versatile formatted print messages.
In Squeak I replaced most usages of roundTo: by printShowing(Max)DecimalPlaces:.
Now if it has been added in Pharo and other languages, there must be some use cases I presume.
Maybe the analysis could be carried on these use cases?

Beware, converting a Fraction asScaledDecimal will NOT round.
Only the printString is rounded, but the number keeps its whole precision.
Example (1/3 asScaledDecimal: 1)*3 = 1.0s, not 0.9s.

ScaledDecimals as they are now are just Fraction with a different printString...
Not very much added value.

Nicolas
 
On 10/26/2016 09:58 AM, Nicolas Cellier wrote:


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...



Reply | Threaded
Open this post in threaded view
|

Re: roundTo: strange behavior

Nicolas Cellier
Sorry for being slow minded,
yes of course financial apps is exactly the case where round: would be usefull and NEEDS to be exact.

2016-10-26 14:23 GMT+02:00 test <[hidden email]>:
Hi Nicolas,
yes, i know. suppose you calc some financial thing and one intermediate result will be in $. you have to round this Fraction-result  to 2 decimals. now you use this to further calc basepoints as the final result. you have to convert this to 3 decimals. looking at this final result with 2 decimals can be be irritating for a moment, if you debug the calcs. and <g> btw i never use scaledDecimals.
werner


On 10/26/2016 02:06 PM, Nicolas Cellier wrote:


2016-10-26 13:11 GMT+02:00 test <[hidden email]>:
Hi Nicolas,
regarding rounding Fractions:
i use fractions if i want to get an exact result (eg for comparing the result with Float calculations). if #round: returns a Float all further calcs (with Fractions) will get contaminated, since the rest will become Floats too. Hence the "asScaledDecimal: numberOfWishedDecimal" seems better to me, but i wonder why these transformations at the end are necessary at all? just for the looks? i'd suppose every person, who knows how to use Fractions, also knows how to append a #asScaledDecimal: to a result by himself, should he want that.

taking as an example financial calcs that first use 2 decimals. occasionaly the final result will be basepoints, often small ones like 0.003. with scaledDecimals the result would be (ok, look like) 0 since scaledDecimals also contaminate the calc. of course one could correct this simply with an #asScaledDecimal:3 at the end. nevertheless a first look at the zero result would surprise me for a tenth of a second.
werner


Hi Werner,
I don't know the purpose of round: at all.
Most often this kind of message was used before printing probably because lack of versatile formatted print messages.
In Squeak I replaced most usages of roundTo: by printShowing(Max)DecimalPlaces:.
Now if it has been added in Pharo and other languages, there must be some use cases I presume.
Maybe the analysis could be carried on these use cases?

Beware, converting a Fraction asScaledDecimal will NOT round.
Only the printString is rounded, but the number keeps its whole precision.
Example (1/3 asScaledDecimal: 1)*3 = 1.0s, not 0.9s.

ScaledDecimals as they are now are just Fraction with a different printString...
Not very much added value.

Nicolas
 
On 10/26/2016 09:58 AM, Nicolas Cellier wrote:


2016-10-26 9:14 GMT+02:00 stepharo <[hidden email]>:
Hi nicolas

So what is the solution? We can integrate fast a solution.
I would really like to see them fix in Pharo 60.
I'm writing a book for newbie and this is the third time I change one chapter
so may be I should stop and throw away this chapter.


1) for Fraction:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asFloat

or just replace asFloat if you wish to remain exact:

round: numberOfWishedDecimal
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self * v) rounded / v) asScaledDecimal: numberOfWishedDecimal

2) for Float, it is in 15471:

round: numberOfWishedDecimal
    | v maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    v := 10 raisedTo: numberOfWishedDecimal.
    ^ ((self asFraction * v) rounded / v) asFloat

or if Fraction already answers a Float:

round: numberOfWishedDecimal
    | maxNumberOfDecimals |
    maxNumberOfDecimals := self class precision - 1 - (self exponent max: self class emin).
    maxNumberOfDecimals < numberOfWishedDecimal ifTrue: [^self].
    ^ self asFraction round: numberOfWishedDecimal
 
It's slower than current implementation, but will round exactly to the nearest Float.
It's possible to have faster implementation up to 22 decimals if you provide a fused-multiply-accumulate primitive...




1234