April 3, 2019 at 5:31 pm #16152
I’m having some issues with floats in MX2. I’m working with currency (2 decimal places). However, when I work with floats everything always comes out with 8 or more decimal digits with slight rounding errors.Monkey12Print Cast<String>(Cast<Float>("0.99"))Print Cast<String>(0.99)
The above example yieldsMonkey120.990000010.98999999999999999
This is making it very difficult to work with currency, and I can’t find any useful rounding functions in the docs.
Any ideas on how I can handle this? Normally it wouldn’t be an issue, but working with currency it’s extremely important that the math comes out correct!April 4, 2019 at 12:12 pm #16156
For anyone else having a similar issue, I just made a simple currency class to ensure decimal rounding is handled as expected. It’s nothing fancy, but does what I need it to do anywaysMonkey12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364Class Currency' Store the whole and fractional parts as integersPrivateField wholeNumber:IntField fractionalNumber:IntPublicMethod New(number:String="0.00")Local decimal:=number.Find(".",0)wholeNumber=Cast<Int>(number.Mid(0,decimal))'0.00fractionalNumber=Cast<Int>(number.Mid(decimal+1,number.Length-1-decimal))EndMethod New(whole:Int,fractional:Int)wholeNumber=wholefractionalNumber=fractionalEndMethod Get:String(prepend:String="")Return prepend+wholeNumber+"."+LPad(fractionalNumber)EndMethod LPad:String(num:Int)If num<10 ThenReturn "0"+numElseReturn numEndifEnd' Currency Operator OverloadsOperator+:Currency(rhs:Currency)Local whole:=wholeNumber+rhs.wholeNumberLocal dec:=fractionalNumber+rhs.fractionalNumberIf dec>99 Thendec-=100whole+=1EndifReturn New Currency(whole,dec)EndOperator-:Currency(rhs:Currency)Local whole:=wholeNumber-rhs.wholeNumberLocal dec:=fractionalNumber-rhs.fractionalNumberIf dec<0 Thendec+=100whole-=1EndifReturn New Currency(whole,dec)EndOperator To:String()Return Get("$")EndEndFunction Main()Local a:=New Currency("1.99")Local b:=New Currency("10.00")Local c:=a+bPrint cEndApril 4, 2019 at 1:00 pm #16157
That looks much more appropriate — you should never use floats for anything that requires accuracy, in any language!
They’re inaccurate by design as they have to work within a set number of bits.
Try this simple, obvious division:Monkey1234567891011Namespace myapp#Import "<std>"Using std..Function Main()Print 1.0 / 10.0End
Here, it prints 0.10000000000000001, but the result may vary on different platforms/targets, and this is to be expected for floating point numbers — they simply can’t represent all decimal numbers accurately.
Anyway, you’ve figured out a solution that looks good for currency.
You must be logged in to reply to this topic.