Rounding float question again

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

Rounding float question again

Denis Kudriashov
Hello.

I know there are many similar questions.

Maybe somebody give me fast answer.

146.015 roundTo: 0.01 => 146.01

I guess internal representation of 146.015 is something like 146.014999999999...
That's why rounding result is 146.01

But how I can round arbitrary float my math root?
How to fix my example to get 146.02?

Best regards,
Denis
Reply | Threaded
Open this post in threaded view
|

Re: Rounding float question again

Nicolas Cellier
Hi Denis,
If you decompose the operation performed by round:

(146.015 / 0.01) rounded * 0.01

'146.015' asFloat is inexact
'0.01' asFloat is inexact
/ 0.01 operation is inexact
'0.01' asFloat is inexact (again)
* 0.01 operation is inexact

That means cumulating 5 inexact operations, how do you say "jouer à la
roulette russe"?

Pharo guys did propose a better scheme

(146.015 * 100.0) rounded / 100.0

Since '100.0' asFloat is exact, that leave only 2 inexact operations
and works much better (and we know the last one rounds exactly).

But if (146.015 asFraction < 146.015s3) then you still have a problem
with inexactness of original value.

I see two solutions for this root problem:
- don't use Float, but Fraction or ScaledDecimals
- use a trick, asMinimalDecimalFraction which I proposed in
http://code.google.com/p/pharo/issues/detail?id=4957 that will convert
('146.015' asFloat) to the exact fraction that is printed
146015/1000...

(x asMinimalDecimalFraction roundTo: 1/100) asFloat would thus be
close to your requirements...

Nicolas

2012/9/7 Denis Kudriashov <[hidden email]>:

> Hello.
>
> I know there are many similar questions.
>
> Maybe somebody give me fast answer.
>
> 146.015 roundTo: 0.01 => 146.01
>
> I guess internal representation of 146.015 is something like
> 146.014999999999...
> That's why rounding result is 146.01
>
> But how I can round arbitrary float my math root?
> How to fix my example to get 146.02?
>
> Best regards,
> Denis

Reply | Threaded
Open this post in threaded view
|

Re: Rounding float question again

Denis Kudriashov
Thank's for your answer.
Only one of your solutions works:
(146.015 asMinimalDecimalFraction roundTo: 1/100) asFloat => 146.02

Others not works:

(146.015 * 100.0) rounded / 100.0 => 146.01
(146.015 asFraction roundTo: 1/100) asFloat => 146.01

2012/9/7 Nicolas Cellier <[hidden email]>
Hi Denis,
If you decompose the operation performed by round:

(146.015 / 0.01) rounded * 0.01

'146.015' asFloat is inexact
'0.01' asFloat is inexact
/ 0.01 operation is inexact
'0.01' asFloat is inexact (again)
* 0.01 operation is inexact

That means cumulating 5 inexact operations, how do you say "jouer à la
roulette russe"?

Pharo guys did propose a better scheme

(146.015 * 100.0) rounded / 100.0

Since '100.0' asFloat is exact, that leave only 2 inexact operations
and works much better (and we know the last one rounds exactly).

But if (146.015 asFraction < 146.015s3) then you still have a problem
with inexactness of original value.

I see two solutions for this root problem:
- don't use Float, but Fraction or ScaledDecimals
- use a trick, asMinimalDecimalFraction which I proposed in
http://code.google.com/p/pharo/issues/detail?id=4957 that will convert
('146.015' asFloat) to the exact fraction that is printed
146015/1000...

(x asMinimalDecimalFraction roundTo: 1/100) asFloat would thus be
close to your requirements...

Nicolas

2012/9/7 Denis Kudriashov <[hidden email]>:
> Hello.
>
> I know there are many similar questions.
>
> Maybe somebody give me fast answer.
>
> 146.015 roundTo: 0.01 => 146.01
>
> I guess internal representation of 146.015 is something like
> 146.014999999999...
> That's why rounding result is 146.01
>
> But how I can round arbitrary float my math root?
> How to fix my example to get 146.02?
>
> Best regards,
> Denis


cbc
Reply | Threaded
Open this post in threaded view
|

Re: Rounding float question again

cbc
On Fri, Sep 7, 2012 at 7:41 AM, Denis Kudriashov <[hidden email]> wrote:
> Thank's for your answer.
> Only one of your solutions works:
> (146.015 asMinimalDecimalFraction roundTo: 1/100) asFloat => 146.02
>
> Others not works:
>
> (146.015 * 100.0) rounded / 100.0 => 146.01
> (146.015 asFraction roundTo: 1/100) asFloat => 146.01
>

Another option it to load FixedDecimal, and use it for you fixed place work:

('146.015' asFixedDecimal: 3) roundTo: ('0.01' asFixedDecimal: 2) ==> 146.02

(Yes, Nicolas, I still haven't come up with a short way of specifying
FixedDecimals, but it will still load into Pharo without an issue.)

http://www.squeaksource.com/FixedDecimal.html

-Chris

Reply | Threaded
Open this post in threaded view
|

Re: Rounding float question again

Nicolas Cellier
In reply to this post by Denis Kudriashov
2012/9/7 Denis Kudriashov <[hidden email]>:

> Thank's for your answer.
> Only one of your solutions works:
> (146.015 asMinimalDecimalFraction roundTo: 1/100) asFloat => 146.02
>
> Others not works:
>
> (146.015 * 100.0) rounded / 100.0 => 146.01
> (146.015 asFraction roundTo: 1/100) asFloat => 146.01
>
>

That's expected, '146.015' asFloat is already smaller than
(146015/1000) so if you convert the float value asFraction or
asScaledDecimal, it's too late, rounding error is already there. You
have to use Fraction, ScaledDecimal or FixedDecimal of Chris right
from the beginning, and don't use Float at all.

> 2012/9/7 Nicolas Cellier <[hidden email]>
>>
>> Hi Denis,
>> If you decompose the operation performed by round:
>>
>> (146.015 / 0.01) rounded * 0.01
>>
>> '146.015' asFloat is inexact
>> '0.01' asFloat is inexact
>> / 0.01 operation is inexact
>> '0.01' asFloat is inexact (again)
>> * 0.01 operation is inexact
>>
>> That means cumulating 5 inexact operations, how do you say "jouer à la
>> roulette russe"?
>>
>> Pharo guys did propose a better scheme
>>
>> (146.015 * 100.0) rounded / 100.0
>>
>> Since '100.0' asFloat is exact, that leave only 2 inexact operations
>> and works much better (and we know the last one rounds exactly).
>>
>> But if (146.015 asFraction < 146.015s3) then you still have a problem
>> with inexactness of original value.
>>
>> I see two solutions for this root problem:
>> - don't use Float, but Fraction or ScaledDecimals
>> - use a trick, asMinimalDecimalFraction which I proposed in
>> http://code.google.com/p/pharo/issues/detail?id=4957 that will convert
>> ('146.015' asFloat) to the exact fraction that is printed
>> 146015/1000...
>>
>> (x asMinimalDecimalFraction roundTo: 1/100) asFloat would thus be
>> close to your requirements...
>>
>> Nicolas
>>
>> 2012/9/7 Denis Kudriashov <[hidden email]>:
>> > Hello.
>> >
>> > I know there are many similar questions.
>> >
>> > Maybe somebody give me fast answer.
>> >
>> > 146.015 roundTo: 0.01 => 146.01
>> >
>> > I guess internal representation of 146.015 is something like
>> > 146.014999999999...
>> > That's why rounding result is 146.01
>> >
>> > But how I can round arbitrary float my math root?
>> > How to fix my example to get 146.02?
>> >
>> > Best regards,
>> > Denis
>>
>

cbc
Reply | Threaded
Open this post in threaded view
|

Re: Rounding float question again

cbc
On Fri, Sep 7, 2012 at 10:34 AM, Nicolas Cellier
<[hidden email]> wrote:

> 2012/9/7 Denis Kudriashov <[hidden email]>:
>> Thank's for your answer.
>> Only one of your solutions works:
>> (146.015 asMinimalDecimalFraction roundTo: 1/100) asFloat => 146.02
>>
>> Others not works:
>>
>> (146.015 * 100.0) rounded / 100.0 => 146.01
>> (146.015 asFraction roundTo: 1/100) asFloat => 146.01
>>
>>
>
> That's expected, '146.015' asFloat is already smaller than
> (146015/1000) so if you convert the float value asFraction or
> asScaledDecimal, it's too late, rounding error is already there. You
> have to use Fraction, ScaledDecimal or FixedDecimal of Chris right
> from the beginning, and don't use Float at all.
>

If you used ScaledDecimal, you will need to make sure that all parts
of it are ScaledDecimal, too - no mixing of Floats anywhere:

This doesn't work:
    146.015s3 roundTo: 0.01 => 146.01
but this does
    146.015s3 roundTo: 0.01s2 => 146.02s2

-Chris