The behaviour of ScaledDecimal in Squeak and Pharo is
- different from what the ANSI Smalltalk standard says
- different from what other Smalltalks do (not that they agree)
- completely different from decimal arithmetic in COBOL, PL/I, or SQL
- seriously confusing.

What you EXPECT is an exact rational number that is equal to an
integer divided by a power of 10, so that the printed
representation faithfully represents the value with no error.
What you GET in Pharo is a rational number that PRINTS with
a given number of decimal places but that is all.

Thus we expect that
�� x := 10/3 asScaledDecimal: 2.
�� x asString ==> '3.33s2'
�� y := x+x+x.
�� y asString ==> '9.99s2'
But no, y asString => '10.00s2'.

Here's what the comment in the VW class FixedPoint says:
"There are two possible ways to express FixedPoint numbers.�� One is as a scaled Integer, but the problem here is that you can lose precision during intermediate calculations.�� For example, a property that seems useful is that the calculation (1.000 / 7 * 7) should give you back the number 1.000.

For this reason, we have adopted an alternative representation, which is a slight variation on Fraction.�� The number is expressed as the ratio of a numerator to a denominator, with the addition of a precision that is used for printing and for rounding.�� The number is not usually rounded off to its scale, but if an intermediate result must be rounded to its scale before being used, the messages #roundedToScale and #truncatedToScale may be used."

The last sentence in the first paragraph is one I cannot agree with.
If I want a calculation where (1/7 * 7) gives me back 1, then I use
exact Fractions. If I am using ScaledDecimal, it is because I *want*
fixed point decimal numbers, with the properties appropriate to fixed
point decimal numbers.�� Wanting something that I could use to talk to
databases like MariaDB I found that I had to write my own FixedPoint
class, only to find that VW called ScaledDecimal FixedPoint.�� *Sigh*.

Unless and until the current ScaledDecimal is ripped out and buried
in an unmarked grave at a crossroad with a stake through its heart,
you may wish to add VW-compatibility methods

roundedToScale
���� |t|
���� t := 10 raisedToInteger: scale.
���� ^(numerator * t / denominator) rounded / t asScaledDecimal: scale

truncatedToScale
���� |t|
���� t := 10 raisedToInteger: scale.
���� ^(numerator * t / denominator) truncated / t asScaledDecimal: scale

and then use

�� aScaledDecimal roundedToScale = anotherOne roundedToScale

Note that the ANSI standard, which was agreed to by a whole bunch of
Smalltalk experts, says "A <scaledDecimal> converted to a <Fraction>
will be a fraction having the same numeric value but having an integer
numerator and a denominator which is ten raised to
the power of the <scaledDecimal>���s scale factor."
Try "(10.00s2 / 3) asFraction" in your Smalltalk, and if the
result has a denominator of 3, SOMEONE stuffed up.




On Tue, 1 Sep 2020 at 16:08, Esteban Maringolo <emaringolo@gmail.com> wrote:
Hi,

I was doing some basic calculations based on a formula, and I wanted
to convert the result to a scaled decimal in order to avoid having
these "loose" decimals in 10th position or something similar.

So I did the following:
82 - (2 * 35.9) - (0 / 2) * (113/121) asScaledDecimal: 1 -> 9.5s1

But When I do this in a test:
(82 - (2 * 35.9) - (0 / 2) * (113/121) asScaledDecimal: 1) = 9.5s1

It fails because the comparison returns false.

I guess this is the proper behavior, but I'd expected that the
conversion from a Float to a scaled decimal would have eliminated the
extra precision from the formula.

I can do a roundTo: 0.1 before converting, but I'd like to know what
would be the proper way of dealing with this.

Thanks!

Esteban A. Maringolo