Hi
there,
I'm geting this unexpected result
from a Squeak 3.9 final 7067 image.
I need to display money values
with two digits. Has anybody a sugestion to correctly achieve
this?
thanks,
|
On 22-Nov-07, at 10:03 AM, Sebastian Sastre wrote:
First and most important - don't maintain money as floating point numbers. Second - never do simple compares of floating point numbers. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Strange OpCodes: FSRA: Forms Skip and Run-Away |
I can only agree and add "use ScaledDecimal".
5.3s2 Beware, Squeak::ScaledDecimal does truncate rather than round when printing... (http://bugs.squeak.org/view.php?id=5693) You might have to change this behavior... Also beware of storeOn: (very minor, who is using storeOn:?). Nicolas tim Rowledge a écrit : > > On 22-Nov-07, at 10:03 AM, Sebastian Sastre wrote: > >> Hi there, >> >> I'm geting this unexpected result from a Squeak 3.9 final 7067 image. >> >> I need to display money values with two digits. Has anybody a >> sugestion to correctly achieve this? > > First and most important - don't maintain money as floating point numbers. > Second - never do simple compares of floating point numbers. > > > tim > -- > tim Rowledge; [hidden email]; http://www.rowledge.org/tim > Strange OpCodes: FSRA: Forms Skip and Run-Away > > > > ------------------------------------------------------------------------ > > |
In reply to this post by timrowledge
Thanks Tim,
may be I should clarify that it's
only for presentation. The mone value is stored as anMeasure of it's monetary
unit in the Aconcagua framework.
But I'm curious about your answer.
Let's supose the user enters in some input widget with keyboard the
'5.30' value. That will end as a Float at some point. Do you suggest I
convert that to a ScaledDecimal? (to store/comare, etc)?
I'm evaluating
this:
(5.3 asScaledDecimal: 2)
and also obtainig: '
5.29s2'
so I'm still lost about
it,
thanks,
|
On 22-Nov-07, at 11:00 AM, Sebastian Sastre wrote:
That must surely count as a bug and I'd hazard a guess that it happens because some code is comparing floats; I've not looked at the code but I've seen it too many times not to suspect it. As for your input widget, I'd try to make it give you the string and directly convert that to a 2dp scaled decimal rather than letting it give you a float. If there isn't a String>asScaledFloat: type method then I guess you get to write it :-) tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim All the simple programs have been written, and all the good names taken. |
In reply to this post by Sebastian Sastre-2
On 11/22/07, Sebastian Sastre <[hidden email]> wrote:
> Let's supose the user enters in some > input widget with keyboard the '5.30' value. That will end as a Float at > some point. Why will it? We're talking about monetary units. If you start with a string like '5.30', meaning 530 monetary units, it won't "end as a Float" all by itself. If somebody somewhere wrote code that converted it to floating point, that's a bug. Don't be misled by what looks like a decimal point. If you're working with money, you don't want floating point, no matter what your programming language. Floating point will lose tiny bits due to roundoff; but money numbers are almost always integral numbers of cents, and you don't want to lose any of them. Floating point may be needed to perform some calculations along the way, but you'll use integers to get the books to balance. ObSqueak: 5.30 asFraction Cheers! --Tom Phoenix |
Tome is right. Don't use a Float
In Smalltalk, use 5.30s2. 5.3 machine representation is not 53/10 though it looks like, and though major Smalltalk dialects will answer true to 53/10=5.3 (i think they should not - see http://bugs.squeak.org/view.php?id=3374 and http://www.lispworks.com/documentation/lcl50/aug/aug-170.html). You can check it with 5.3 asTrueFraction, that is (2r10101001100110011001100110011001100110011001100110011/2r100000000000000000000000000000000000000000000000000). And if it prints 5.29s2, then it is because of http://bugs.squeak.org/view.php?id=5693 that you did not care to read. * 5.3 asTrueFraction < (53/10) * ScaledDecimal use truncated print, => you have the explanation. The only thing you should try if you cannot get read of Float because of 3rd party code is: (5.3 asScaledDecimal: 2) roundTo: 0.01s2. Nicolas Tom Phoenix a écrit : > On 11/22/07, Sebastian Sastre <[hidden email]> wrote: > >> Let's supose the user enters in some >> input widget with keyboard the '5.30' value. That will end as a Float at >> some point. > > Why will it? > > We're talking about monetary units. If you start with a string like > '5.30', meaning 530 monetary units, it won't "end as a Float" all by > itself. If somebody somewhere wrote code that converted it to floating > point, that's a bug. > > Don't be misled by what looks like a decimal point. If you're working > with money, you don't want floating point, no matter what your > programming language. Floating point will lose tiny bits due to > roundoff; but money numbers are almost always integral numbers of > cents, and you don't want to lose any of them. Floating point may be > needed to perform some calculations along the way, but you'll use > integers to get the books to balance. > > ObSqueak: 5.30 asFraction > > Cheers! > > --Tom Phoenix > > |
nicolas cellier a écrit :
> The only thing you should try if you cannot get read of Float because of > 3rd party code is: Hem, get rid... > > (5.3 asScaledDecimal: 2) roundTo: 0.01s2. > or simply: 5.3 roundTo: 0.01s2 |
In reply to this post by timrowledge
Ok, don't beat me.. I'm not proud of this but I have to
use until I manage to have something better.
String>>asScaledDecimal:
aQuantityOfDigits
"Answers the scaled decimal with aQuantityOfDigits of precision represented by the receiver." ^ [:number| number isZero ifTrue:[0 asFloat asScaledDecimal: aQuantityOfDigits] ifFalse:[number asScaledDecimal: aQuantityOfDigits]] value: self asNumber so my converter can do this depending on it's own
configuration (not only used for money):
MVPNumberToText>>rightToLeft:
aString
"Answers the result of converting aString to a Number or aScaledDecimal." ^self
hasInputDigits
ifTrue:[aString asScaledDecimal: inputDigits] ifFalse:[aString asNumber] Adding the horrible hack:
ScaledDecimal>>printOn: aStream
"Reimplementation - Object 'printing' method." | aFraction tmpFractionPart | self < 0 ifTrue: [aStream nextPut: $-]. aFraction := fraction abs. aStream nextPutAll: aFraction rounded printString. scale = 0 ifTrue: [^ aStream nextPutAll: 's0']. aStream nextPut: $.. tmpFractionPart := aFraction fractionPart. 1 to: scale do: [:dummy | tmpFractionPart := tmpFractionPart * 10. (10 <= tmpFractionPart rounded) ifTrue:[aStream nextPut: $0] ifFalse:[aStream nextPut: (Character digitValue: tmpFractionPart rounded)]. tmpFractionPart := tmpFractionPart fractionPart]. I was able to make the values to
behave,
thanks,
|
On Nov 22, 2007, at 21:39 , Sebastian Sastre wrote:
> Ok, don't beat me.. I promise, at least if you stop posting HTML messages to the list. - Bert - |
In reply to this post by Tom Phoenix
> -----Mensaje original-----
Even if you don't use computers to achieve that, when you make monetary
> De: [hidden email] > [mailto:[hidden email]] En > nombre de Tom Phoenix > Enviado el: Jueves, 22 de Noviembre de 2007 17:59 > Para: The general-purpose Squeak developers list > Asunto: Re: 5.3 printShowingDecimalPlaces: 2 displays '5.29' > insteadof'5.30' > > On 11/22/07, Sebastian Sastre <[hidden email]> wrote: > > > Let's supose the user enters in some > > input widget with keyboard the '5.30' value. That will end > as a Float > > at some point. > > Why will it? > > We're talking about monetary units. If you start with a > string like '5.30', meaning 530 monetary units, it won't "end > as a Float" all by itself. If somebody somewhere wrote code > that converted it to floating point, that's a bug. > values to pass trhough functions they *are* mathematically represented as float numeric values. At some point we simplify presentations (like the balance books you mention) of the values. I certainly agree with you about units. In fact there are equivalence units. 100 cents are 1 dollar, 4 quarters also are equal to 1 dollar and 100 cents. Aconcagua framework seems to deal quite well with that trough it's Measures (and amount and a unit). For monetary measures I think I'll store scaled decimal amounts to gain the accuracy you propose. > Don't be misled by what looks like a decimal point. If you're > working with money, you don't want floating point, no matter > what your programming language. Floating point will lose tiny > bits due to roundoff; but money numbers are almost always > integral numbers of cents, and you don't want to lose any of > them. Floating point may be needed to perform some > calculations along the way, but you'll use integers to get > the books to balance. > I agree. With measures I think I'll be able to achieve that, by using scaled decimanls in the amounts of the measures, and the rounding will be performed only in presentation time by the converter of the widget and not in the internal process, formulas or calculation of the value. Cheers! Sebastian > ObSqueak: 5.30 asFraction > > Cheers! > > --Tom Phoenix > |
In reply to this post by Sebastian Sastre-2
Sebastian Sastre a écrit :
> Ok, don't beat me.. I'm not proud of this but I have to use until I > manage to have something better. > > String>>asScaledDecimal: aQuantityOfDigits > "Answers the scaled decimal with aQuantityOfDigits > of precision represented by the receiver." > > ^ [:number| > number isZero > ifTrue:[0 asFloat asScaledDecimal: aQuantityOfDigits] > ifFalse:[number asScaledDecimal: aQuantityOfDigits]] value: self > asNumber > Yes, it should be (ScaledDecimal readFrom: self), but this one would anwer a Float... > so my converter can do this depending on it's own configuration (not > only used for money): > > MVPNumberToText>>rightToLeft: aString > "Answers the result of converting aString to a Number or aScaledDecimal." > > ^self hasInputDigits > ifTrue:[aString asScaledDecimal: inputDigits] > ifFalse:[aString asNumber] > > Adding the horrible hack: > > ScaledDecimal>>printOn: aStream > "Reimplementation - Object 'printing' method." > | aFraction tmpFractionPart | > self < 0 ifTrue: [aStream nextPut: $-]. > aFraction := fraction abs. > aStream nextPutAll: aFraction rounded printString. > scale = 0 ifTrue: [^ aStream nextPutAll: 's0']. > aStream nextPut: $.. > tmpFractionPart := aFraction fractionPart. > 1 to: scale > do: > [:dummy | > tmpFractionPart := tmpFractionPart * 10. > (10 <= tmpFractionPart rounded) > ifTrue:[aStream nextPut: $0] > ifFalse:[aStream nextPut: (Character digitValue: tmpFractionPart > rounded)]. > tmpFractionPart := tmpFractionPart fractionPart]. > > I was able to make the values to behave, > > thanks, > > > Sebastian Sastre > > > > > ------------------------------------------------------------------------ > *De:* [hidden email] > [mailto:[hidden email]] *En nombre de > *tim Rowledge > *Enviado el:* Jueves, 22 de Noviembre de 2007 17:10 > *Para:* The general-purpose Squeak developers list > *Asunto:* Re: 5.3 printShowingDecimalPlaces: 2 displays '5.29' > insteadof'5.30' > > > On 22-Nov-07, at 11:00 AM, Sebastian Sastre wrote: > >> Thanks Tim, >> >> may be I should clarify that it's only for presentation. The >> mone value is stored as anMeasure of it's monetary unit in the >> Aconcagua framework. >> >> But I'm curious about your answer. Let's supose the user >> enters in some input widget with keyboard the '5.30' value. That >> will end as a Float at some point. Do you suggest I convert that >> to a ScaledDecimal? (to store/comare, etc)? >> >> I'm evaluating this: >> >> (5.3 asScaledDecimal: 2) >> and also obtainig: ' 5.29s2' > > That must surely count as a bug and I'd hazard a guess that it > happens because some code is comparing floats; I've not looked at > the code but I've seen it too many times not to suspect it. > > As for your input widget, I'd try to make it give you the string and > directly convert that to a 2dp scaled decimal rather than letting it > give you a float. If there isn't a String>asScaledFloat: type method > then I guess you get to write it :-) > > > tim > -- > tim Rowledge; [hidden email]; http://www.rowledge.org/tim > All the simple programs have been written, and all the good names taken. > > > > ------------------------------------------------------------------------ > > |
In reply to this post by Nicolas Cellier-3
> And if it prints 5.29s2, then it is because of
> http://bugs.squeak.org/view.php?id=5693 that you did not care to read. > Hey! I was reading that. That's why I'm now converting values to scaled decimals without even passing the string representation entered in the widget to number conversion through floats! > * 5.3 asTrueFraction < (53/10) > * ScaledDecimal use truncated print, > => you have the explanation. > > The only thing you should try if you cannot get read of Float > because of 3rd party code is: > > (5.3 asScaledDecimal: 2) roundTo: 0.01s2. > > Nicolas > Thanks for helping so accurately, Sebastian |
In reply to this post by Bert Freudenberg
Hey I didn't know that was causing annoyances. Users should be informed
somehow. Switching to plain text now... Sebastian Sastre > -----Mensaje original----- > De: [hidden email] > [mailto:[hidden email]] En > nombre de Bert Freudenberg > Enviado el: Jueves, 22 de Noviembre de 2007 18:42 > Para: The general-purpose Squeak developers list > Asunto: Re: 5.3 printShowingDecimalPlaces: 2 displays '5.29' > insteadof'5.30' > > On Nov 22, 2007, at 21:39 , Sebastian Sastre wrote: > > > Ok, don't beat me.. > > I promise, at least if you stop posting HTML messages to the list. > > - Bert - > > > |
In reply to this post by Sebastian Sastre-2
You're welcome,
and to push library polishing and consistency further, I propose that (ScaledDecimal readFrom: '5.30') behave as you expect. Try patch at http://bugs.squeak.org/view.php?id=6779 Nicolas Sebastian Sastre a écrit : >> And if it prints 5.29s2, then it is because of >> http://bugs.squeak.org/view.php?id=5693 that you did not care to read. >> > Hey! I was reading that. That's why I'm now converting values to scaled > decimals without even passing the string representation entered in the > widget to number conversion through floats! > >> * 5.3 asTrueFraction < (53/10) >> * ScaledDecimal use truncated print, >> => you have the explanation. >> >> The only thing you should try if you cannot get read of Float >> because of 3rd party code is: >> >> (5.3 asScaledDecimal: 2) roundTo: 0.01s2. >> >> Nicolas >> > > Thanks for helping so accurately, > > Sebastian > > > |
In reply to this post by Sebastian Sastre-2
just a kick comment.
We use Fraction, no ScaledDecimal, no Float. We made some changes to fraction to work faster. We didn't see big performance diferences with ScaledDecimal. We use measures to represent all type of quantities of some financial instrument. For example: 100 dollars 100 IBM 100 bond (any bond) etc. Bye, Hernan. On Nov 22, 2007 5:50 PM, Sebastian Sastre <[hidden email]
> wrote: > -----Mensaje original----- |
In reply to this post by Nicolas Cellier-3
Besides that, I think that #printShowingDecimalPlaces: needs a serius fix.
Evaluating for this float: 302.46 printShowingDecimalPlaces: 2 Result displaying it is '302.45' We calculate quite well by using fractions and scaled decimals but we also need good text representations of those fine values. Any known patch for that? thanks, Sebastian Sastre > -----Mensaje original----- > De: [hidden email] > [mailto:[hidden email]] En > nombre de nicolas cellier > Enviado el: Jueves, 22 de Noviembre de 2007 19:52 > Para: [hidden email] > Asunto: Re: 5.3 printShowingDecimalPlaces: 2 displays '5.29' > insteadof'5.30' > > You're welcome, > and to push library polishing and consistency further, I > propose that (ScaledDecimal readFrom: '5.30') behave as you expect. > Try patch at http://bugs.squeak.org/view.php?id=6779 > > Nicolas > > Sebastian Sastre a écrit : > >> And if it prints 5.29s2, then it is because of > >> http://bugs.squeak.org/view.php?id=5693 that you did not > care to read. > >> > > Hey! I was reading that. That's why I'm now converting values to > > scaled decimals without even passing the string > representation entered > > in the widget to number conversion through floats! > > > >> * 5.3 asTrueFraction < (53/10) > >> * ScaledDecimal use truncated print, > >> => you have the explanation. > >> > >> The only thing you should try if you cannot get read of > Float because > >> of 3rd party code is: > >> > >> (5.3 asScaledDecimal: 2) roundTo: 0.01s2. > >> > >> Nicolas > >> > > > > Thanks for helping so accurately, > > > > Sebastian > > > > > > > > |
In reply to this post by hernan.wilkinson
Hernan Wilkinson a écrit :
> just a kick comment. > We use Fraction, no ScaledDecimal, no Float. We made some changes to > fraction to work faster. We didn't see big performance diferences with > ScaledDecimal. > We use measures to represent all type of quantities of some financial > instrument. For example: > 100 dollars > 100 IBM > 100 bond (any bond) > etc. > > Bye, > Hernan. > You must be right. ScaledDecimal are just fractions wrapper with special methods to read and print... ...that do not necessarily match your required monetary format (thousand separator, localized decimal point, no awfull s2 like in 5.30s2, append or prepend monetary symbol etc...). So you inevitably end up with a monetary object having its own read/print methods, and ScaledDecimal is not of much help then... If your Fraction optimisations are significative, please share on Mantis or something. Cheers Nicolas |
In reply to this post by Sebastian Sastre-2
Obviously, this method is weak!
Main thing is to check mantis http://bugs.squeak.org/ If not reported, please open a bug report. If you have time, create a SUnit TestCase, file it out and upload test on bug report. Even better, create and upload a patch. This time, it is already there http://bugs.squeak.org/view.php?id=5640 If the patch rocks, you review it carefully, and propose it as candidate for image integration at http://wiki.squeak.org/squeak/5934 Cheers Sebastian Sastre a écrit : > Besides that, I think that #printShowingDecimalPlaces: needs a serius fix. > Evaluating for this float: > > 302.46 printShowingDecimalPlaces: 2 > > Result displaying it is '302.45' > > We calculate quite well by using fractions and scaled decimals but we also > need good text representations of those fine values. > > Any known patch for that? > > thanks, > > Sebastian Sastre > > >> -----Mensaje original----- >> De: [hidden email] >> [mailto:[hidden email]] En >> nombre de nicolas cellier >> Enviado el: Jueves, 22 de Noviembre de 2007 19:52 >> Para: [hidden email] >> Asunto: Re: 5.3 printShowingDecimalPlaces: 2 displays '5.29' >> insteadof'5.30' >> >> You're welcome, >> and to push library polishing and consistency further, I >> propose that (ScaledDecimal readFrom: '5.30') behave as you expect. >> Try patch at http://bugs.squeak.org/view.php?id=6779 >> >> Nicolas >> >> Sebastian Sastre a écrit : >>>> And if it prints 5.29s2, then it is because of >>>> http://bugs.squeak.org/view.php?id=5693 that you did not >> care to read. >>> Hey! I was reading that. That's why I'm now converting values to >>> scaled decimals without even passing the string >> representation entered >>> in the widget to number conversion through floats! >>> >>>> * 5.3 asTrueFraction < (53/10) >>>> * ScaledDecimal use truncated print, >>>> => you have the explanation. >>>> >>>> The only thing you should try if you cannot get read of >> Float because >>>> of 3rd party code is: >>>> >>>> (5.3 asScaledDecimal: 2) roundTo: 0.01s2. >>>> >>>> Nicolas >>>> >>> Thanks for helping so accurately, >>> >>> Sebastian >>> >>> >>> >> > > > |
Free forum by Nabble | Edit this page |