Thanks ***A LOT*** nicolas.
I've put a single slice in the inbox for the 3 issues because they all
are related.
See slice comment:
For Float, implement guard to prevent overflow (15471), and use exact
representation for intermediate results (asFraction) so as to avoid
double rounding problems (15473)
For Fraction (15472), choose an exact representation for result rather
than Float. This is because such method is particularly usefull for
financial/monetary applications.
2016-10-26 17:28 GMT+02:00 stepharo <[email protected]
<mailto:[email protected]>>:
Le 26/10/16 à 14:52, Nicolas Cellier a écrit :
Sorry for being slow minded,
yes of course financial apps is exactly the case where round:
would be usefull and NEEDS to be exact.
so what is the solution?
I'm lost again.
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 <[email protected]
<mailto:[email protected]>>:
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 <[email protected]
<mailto:[email protected]>>:
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...