[ANN] FixedDecimals

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

[ANN] FixedDecimals

cbc
Hi.

I've just release a package FixedDecimal on SqueakSource.

A FixedDecimal is similar to a ScaledDecimal, but different in certain select ways.  It's primary purpose was to be able to represent precise decimals for such things as representing money - where ScaledDecimals leave something to be desired.  For instance, with ScaledDecimals, you get:
(33.333s withScale:2) + (33.333s withScale:2)   print it yields 66.67s
but with FixedDecimals, you would get:
(33.333 asFixedDecimal: 2) + (33.333 asFixedDecimal: 2)    print it yields 66.66.
So, FixedDecimals round the numbers to the exact scale you specify - converting a float to a FixedDecimal and back will not necessarily return the starting number, unlike ScaledDecimals.

Most simple arithmetic is defined for FixedDecimals, but not all methods that probably should be (it's getting late and I'm going away for the weekend - thought I'd publish what I have).

Thanks,
Chris


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] FixedDecimals

Jason Johnson-5
nice.

On 8/31/07, Chris Cunningham <[hidden email]> wrote:

> Hi.
>
> I've just release a package FixedDecimal on SqueakSource.
>
> A FixedDecimal is similar to a ScaledDecimal, but different in certain
> select ways.  It's primary purpose was to be able to represent precise
> decimals for such things as representing money - where ScaledDecimals leave
> something to be desired.  For instance, with ScaledDecimals, you get:
> (33.333s withScale:2) + (33.333s withScale:2)   print it yields 66.67s
> but with FixedDecimals, you would get:
> (33.333 asFixedDecimal: 2) + (33.333 asFixedDecimal: 2)    print it yields
> 66.66.
> So, FixedDecimals round the numbers to the exact scale you specify -
> converting a float to a FixedDecimal and back will not necessarily return
> the starting number, unlike ScaledDecimals.
>
> Most simple arithmetic is defined for FixedDecimals, but not all methods
> that probably should be (it's getting late and I'm going away for the
> weekend - thought I'd publish what I have).
>
> Thanks,
> Chris
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: [ANN] FixedDecimals

Nicolas Cellier-3
In reply to this post by cbc
Interesting, however current version FixedDecimals.cbc.12.mcz is bugged.

example:

(-53/10 asFixedDecimal: 2) fractionPart.

Some suggestions:
- why maintaining so many forms in parallel ?
   Not bug-proof, you happen to update one form not the other...
   sign is not handled in part1 nor part2
- negated should create a new instance
   rather than modifying the number in place
- FixedDecimals does not implement hash,
   therefore cannot be stored in a Dictionary.
   Particularly, cannot be stored in a workspace variable.
   I suggest hash ^self asFraction hash
- likewise, implement all subclassResponsibility
        ( 5/3) * (5/3 asFixedDecimal: 2).
        ( 2.0s1) * (5/3 asFixedDecimal: 2).
        (5/3 asFixedDecimal: 2) reciprocal.
- coercion depends on receiver:
        | a b |
        a := (53/10 asFixedDecimal: 2).
        b := 5.3.
        { (a+b) class.
        (b+a) class. } "is {FixedDecimal . Float}"
- maybe add another rounding mode in arithmetic (to nearest even...)
- create a specific notation for transparent read/write, like 5.30f
  (requires some easy support in Number class>>readFrom: or NumberParser)

 From algebraic point of view, the main concern is that some numbers
might not have any reciprocal...
Unless the reciprocal is a Fraction, and arithmetic op coerce to Fraction...
But, eh, this is just the case of Float:
| f |
f := (8872240531573379/9007199254740992) asFloat.
f * f reciprocal - 1

Cheers

Nicolas

Chris Cunningham a écrit :

> Hi.
>
> I've just release a package FixedDecimal on SqueakSource.
>
> A FixedDecimal is similar to a ScaledDecimal, but different in certain
> select ways.  It's primary purpose was to be able to represent precise
> decimals for such things as representing money - where ScaledDecimals
> leave something to be desired.  For instance, with ScaledDecimals, you get:
> (33.333s withScale:2) + (33.333s withScale:2)   print it yields 66.67s
> but with FixedDecimals, you would get:
> (33.333 asFixedDecimal: 2) + (33.333 asFixedDecimal: 2)    print it
> yields 66.66.
> So, FixedDecimals round the numbers to the exact scale you specify -
> converting a float to a FixedDecimal and back will not necessarily
> return the starting number, unlike ScaledDecimals.
>
> Most simple arithmetic is defined for FixedDecimals, but not all methods
> that probably should be (it's getting late and I'm going away for the
> weekend - thought I'd publish what I have).
>
> Thanks,
> Chris
>
>
> ------------------------------------------------------------------------
>
>


cbc
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] FixedDecimals

cbc
Hi Nocolas,

Thanks for the review.  I have not actually used this for arithmetic yet, I added that in a couple of hours before publishing this.  Previously this has been used to represent the decimal values that I needed to use to load into a database using a fixed length representation.  This need influenced my design quite a bit.  However, without arithmetic, it isn't very useful for many other people (or myself going forward).

As to your points;


(-53/10 asFixedDecimal: 2) fractionPart.

Right.  I  did not finish adding in all of the protocol that should be added.  I will  continue to do this over the next few days as I have time.  For now, this works:

(-53/10 asFixedDecimal: 2) fractionPart. - 0.30

- why maintaining so many forms in parallel ?
   Not bug-proof, you happen to update one form not the other...
   sign is not handled in part1 nor part2

This is a result of  what I was originally using it for, which works pretty well (until I introduce bugs, that is).  Keeping the various different forms there does make certain transformations much easier to handle.  However, I might take a look at other ways to handle this.  (Also, this repository is open, is if anyone wants to add a different representation, they are free to do so).

- negated should create a new instance
   rather than modifying the number in place

Yes, that was a bad choice.  It is now making a new instance.

- FixedDecimals does not implement hash,
   therefore cannot be stored in a Dictionary.
   Particularly, cannot be stored in a workspace variable.
   I suggest hash ^self asFraction hash

This is now fixed, as you suggested.  Although I may tweak this (is there a good hash tester available for Squeak?)

- likewise, implement all subclassResponsibility

Right.  I'm working on that...  

        ( 5/3) * (5/3 asFixedDecimal: 2).
        ( 2.0s1) * (5/3 asFixedDecimal: 2).
        (5/3 asFixedDecimal: 2) reciprocal.

Fixed.  See below.

- coercion depends on receiver:
        | a b |
        a := (53/10 asFixedDecimal: 2).
        b := 5.3.
        { (a+b) class.
        (b+a) class. } "is {FixedDecimal . Float}"

Hmmm.  Yes.  I think I want all arithmetic with FixedDecimals to return a FixedDecimal.  Looking as ScaledDecimals, I notice that what is returned is consistent with for a given other magnitude, but not always the same.  Is there a rational behind which type of number is returned?  Is it spelled out in ANSI?
(Also, while checking this, I noticed that .333 does not give you 0.333 but rather 333.  I wonder if I've coded in a bug like that somewhere else?  If the . is the first part of the method or workspace, it just quitely eats it.)

- maybe add another rounding mode in arithmetic (to nearest even...)

I might add something like that as time permits.  Do you have a use for it?

- create a specific notation for transparent read/write, like 5.30f
  (requires some easy support in Number class>>readFrom: or NumberParser)

Will do.

From algebraic point of view, the main concern is that some numbers
might not have any reciprocal...
Unless the reciprocal is a Fraction, and arithmetic op coerce to Fraction...
But, eh, this is just the case of Float:
| f |
f := (8872240531573379/9007199254740992) asFloat.
f * f reciprocal - 1

Well, this particular number DOES have a reciprocal in FixedDecimals which just happens to be a FixedDecimal.  You just have to specify the scale right:
fd _ (8872240531573379/9007199254740992) asFixedDecimal: 53
rfd _ fd reciprocal
rfd reciprocal
fd * rfd - 1 = 0.00000000000000000000000000000000000000000000000000000
That said, there might be some rational numbers that will not have a reciprocal, but I can't find them.  For instance:
fd _ (1/3) asFixedDecimal: 5  "= 0.33333"
rfd _ fd reciprocal  "= 3.00003"
fd * rfd - 1  "0.00000"

Most of this is now out in SqueakSource.  I'll do some more as time permits.  (Also, all of these changes now have tests, too).

Thanks,
Chris


Reply | Threaded
Open this post in threaded view
|

Re: [ANN] FixedDecimals

Nicolas Cellier-3
Chris Cunningham a écrit :
>
>     - maybe add another rounding mode in arithmetic (to nearest even...)
>
>
> I might add something like that as time permits.  Do you have a use for it?
>

No, but i just wonder if all monetary application will truncate...