[Pharo-project] Rounding float question again
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
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 <dionisiydk@gmail.com>:
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
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 <nicolas.cellier.aka.nice@gmail.com>
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 <dionisiydk@gmail.com>:
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
On Fri, Sep 7, 2012 at 7:41 AM, Denis Kudriashov <dionisiydk@gmail.com> 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
2012/9/7 Denis Kudriashov <dionisiydk@gmail.com>:
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 <nicolas.cellier.aka.nice@gmail.com>
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 <dionisiydk@gmail.com>:
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
On Fri, Sep 7, 2012 at 10:34 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2012/9/7 Denis Kudriashov <dionisiydk@gmail.com>:
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
participants (3)
-
Chris Cunningham -
Denis Kudriashov -
Nicolas Cellier