[Seaside] Money ScaledDecimal is it really *appropriate* ?

David Shaffer cdshaffer at acm.org
Thu Feb 2 18:29:08 CET 2006


Dmitry Dorofeev wrote:

> Hi,
>
> Assuming I have prices with 2 digits after dot I want to calculate VAT
> with 4 digits precision. VAT May be shown still rounded to 2 digits,
> but some clients want to see even 4 digits after dot !!! With high
> turn over made from small sells it is some real money due to rounding
> errors :-)
>
> I made some tests and found a funny example:
>
> a := ScaledDecimal newFromNumber: 6.18 scale: 4.
> b :=  ScaledDecimal newFromNumber: 5 scale: 4.
> a / b   1.2359s4
> a / b printShowingDecimalPlaces: 4 '1.2360'
> 6.18 / 5.0  1.236
>
> why a / b shows 2.2359s4 ?
> but (a / b printShowingDecimalPlaces: 4) shows correct answer
> It makes me nervious....
>
> Thanks.
>

I'd like to second what I believe Colin said about using integers to
represent money.  If you need four digits then that dictates the scale
of your integers.  Maybe ScaledDecimals would do the job, don't know
anything about them, but my experience dictates that it only takes 10
minutes to put together a Money (and/or Currency) class based on this
integer representation and it is well worth the effort.  Attached is one
that I've used in the past...maybe not as robust as you need but you
could probably hack it into your 4-digit form faster than you could
learn about ScaledDecimal...

Maybe somewants to post a more industry hardened version :-)

David

-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 2 February 2006 at 12:26:34 pm'!
Magnitude subclass: #Money
	instanceVariableNames: 'cents'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Grocery-Domain'!

!Money methodsFor: 'accessing' stamp: 'cds 3/27/2005 13:31'!
cents
	^cents! !


!Money methodsFor: 'comparing' stamp: 'cds 3/27/2005 13:35'!
< other
	^self cents < other cents! !

!Money methodsFor: 'comparing' stamp: 'cds 2/2/2006 12:26'!
= other
	^self species = other species and: [self cents = other cents]! !

!Money methodsFor: 'comparing' stamp: 'cds 3/27/2005 13:35'!
hash
	^self cents hash! !


!Money methodsFor: 'arithmetic' stamp: 'cds 3/27/2005 13:36'!
+ other
	^Money cents: self cents + other cents! !


!Money methodsFor: 'initialize-release' stamp: 'cds 3/27/2005 13:31'!
cents: anObject
	cents := anObject! !


!Money methodsFor: 'printing' stamp: 'cds 3/27/2005 19:03'!
printOn: aStream
	aStream nextPutAll: '$'.
	self cents // 100 printOn: aStream.
	aStream nextPut: $..
	self cents \\ 100 < 10 ifTrue: [aStream nextPut: $0].
	cents \\ 100 printOn: aStream.! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

Money class
	instanceVariableNames: ''!

!Money class methodsFor: 'instance creation' stamp: 'cds 3/27/2005 13:30'!
cents: anInteger
	^self new cents: anInteger; yourself! !

!Money class methodsFor: 'instance creation' stamp: 'cds 4/4/2005 12:49'!
zero
	^self cents: 0! !
-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 2 February 2006 at 12:26:48 pm'!

!Integer methodsFor: '*Grocery' stamp: 'cds 3/27/2005 14:04'!
cents
	^self asMoney! !
-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 2 February 2006 at 12:28:26 pm'!
TestCase subclass: #MoneyTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Grocery-Tests'!

!MoneyTest methodsFor: 'tests' stamp: 'cds 3/27/2005 14:06'!
testAddition
	| m1 m2 |
	m1 := 532 cents.
	m2 := 654 cents.
	
	self assert: (m1 + m2) cents = (532 + 654)! !

!MoneyTest methodsFor: 'tests' stamp: 'cds 3/27/2005 14:04'!
testCreation
	| m |
	m := 100 asMoney.
	self assert: m cents = 100.
	
	m := 100 asDollars.
	self assert: m cents = 10000.
	
	m := Money cents: 10.
	self assert: m cents = 10.
	
	m := 965 cents.
	self assert: m cents = 965! !

!MoneyTest methodsFor: 'tests' stamp: 'cds 3/27/2005 19:02'!
testPrinting
	self assert: 965 cents printString = '$9.65'.
	self assert: 430 cents printString = '$4.30'.
	self assert: 502 cents printString = '$5.02'! !


More information about the Seaside mailing list