1. Stange problem with sprintf or trace display
- Posted by AJ_Oxley Mar 13, 2012
- 1132 views
Hello gurus...
My app was adding up dollars and cents but did not balance.
A simplified example of why not is given below:
-- euphoria v4.0.3 windows 2011-06-24 13:43:18 with type_check with trace with warning procedure test() atom a1, a2, a3, a4, a5, a6 sequence s1 trace(1) a1 = 0.77 a2 = a1 * 100 printf(1,"\na2 is " & sprintf("%2d",{a2}) & "\n") -- now the strange part a3 = 66.77 a4 = floor(a3) a5 = a3 - a4 -- 0.77, same as a1 a6 = a5 * 100 -- trace says this is 77 printf(1,"\na6 is " & sprintf("%2d",{a6}) & "!\n") -- 76!! end procedure test() -- the problem exists whenever a6 > 01
This is whacky! any ideas?
2. Re: Stange problem with sprintf or trace display
- Posted by mattlewis (admin) Mar 13, 2012
- 1116 views
Hello gurus...
My app was adding up dollars and cents but did not balance.
A simplified example of why not is given below:
...
This is whacky! any ideas?
In general, you should not use floating point arithmetic for financial purposes. You're seeing rounding errors due to the fact that floating point numbers are stored in binary, and there are many decimal fractions that cannot be represented exactly.
Matt
3. Re: Stange problem with sprintf or trace display
- Posted by AJ_Oxley Mar 13, 2012
- 1120 views
A floating point/rounding problem with a 2 digit atom? Its nowhere near the 31 bit limit!
Strange indeed. Anyway -
If the data input from my user is characters in the format nnnn.cc ,multiple instances.
I have to seperate the cents from the dollars and convert to numeric to add this up.
Can you suggest how to achieve this and avoid the rounding problem?
4. Re: Stange problem with sprintf or trace display
- Posted by mattlewis (admin) Mar 13, 2012
- 1112 views
A floating point/rounding problem with a 2 digit atom? Its nowhere near the 31 bit limit!
It can probably get pretty close. Try, for instance, to precisely express 1/3 as a decimal. The radices are different, but the problem is the same.
Strange indeed. Anyway -
If the data input from my user is characters in the format nnnn.cc ,multiple instances.
I have to seperate the cents from the dollars and convert to numeric to add this up.
Can you suggest how to achieve this and avoid the rounding problem?
The simplest is probably to convert to your smallest unit. In this case, track everything in terms of cents. Then you can convert / format that however you need. Alternatively, you could track dollars and cents separately, and manage the borrowing / carrying manually. Some systems use binary coded decimal (BCD). That's probably not a practical approach for euphoria code.
Matt
5. Re: Stange problem with sprintf or trace display
- Posted by AJ_Oxley Mar 13, 2012
- 1174 views
Thanks Matt,
The problem is that I am trying to save the data as characters, so will need to use value() and sprintf() quite a bit when fetching / displaying / accepting input.
In essence you are suggesting that a user may not enter numeric data as chars that contain a period, because of the rounding errors?
Possible bypass is to have seperate list controls designated for dollars and cents; the user would have to tab accross to the cents.
That won't make me popular!
6. Re: Stange problem with sprintf or trace display
- Posted by ghaberek (admin) Mar 13, 2012
- 1102 views
Thanks Matt,
The problem is that I am trying to save the data as characters, so will need to use value() and sprintf() quite a bit when fetching / displaying / accepting input.
In essence you are suggesting that a user may not enter numeric data as chars that contain a period, because of the rounding errors?
Possible bypass is to have seperate list controls designated for dollars and cents; the user would have to tab accross to the cents.
That won't make me popular!
Just split the number on the decimal and combine the two values:
-- this is straight out of my head, -- it may not work if actually run function decimal_from_string( sequence str ) if find( '.', str ) then sequence parts = split( str, '.' ) sequence val1 = value( str[1] ) sequence val2 = value( str[2] ) return val1[2] + (val2[2] / 100) else -- no decimal here sequence val = value( str ) return val[2] end if end function
-Greg
7. Re: Stange problem with sprintf or trace display
- Posted by AJ_Oxley Mar 13, 2012
- 1155 views
I will experiment with mutiplying the floating point atom by 100 to get integer and then use divide and floor() .. it should work I hope !
Thanks for the help
8. Re: Stange problem with sprintf or trace display
- Posted by mattlewis (admin) Mar 13, 2012
- 1168 views
Thanks Matt,
The problem is that I am trying to save the data as characters, so will need to use value() and sprintf() quite a bit when fetching / displaying / accepting input.
In essence you are suggesting that a user may not enter numeric data as chars that contain a period, because of the rounding errors?
Possible bypass is to have seperate list controls designated for dollars and cents; the user would have to tab accross to the cents.
That won't make me popular!
If rounding errors are a problem, then you can't simply convert a fractional number into an atom. In general, monetary rounding errors are considered problematic.
I think the correct approach is to allow your users to do whatever they're doing, but to handle the data carefully inside your program so that you don't get any rounding errors. This should be completely transparent to a user. It makes things more difficult on you, of course, but there's really no way around this.
Databases tend to store things in different formats for this purpose. I know that in Java, a common way to implement money is to use the BigDecimal class, which makes arithmetic more difficult than "normal" numeric types, but has the bonus of avoiding floating point rounding errors.
I was somewhat surprised that a quick search in the archive didn't turn up any libraries that deal with money. I'm sure someone around here must have some code lying around.
Matt
9. Re: Stange problem with sprintf or trace display
- Posted by mattlewis (admin) Mar 13, 2012
- 1152 views
I will experiment with mutiplying the floating point atom by 100 to get integer and then use divide and floor() .. it should work I hope !
Thanks for the help
Ack! No no no! Don't divide and floor(). That's just a different way to recreate the same headaches you already have.
Matt
10. Re: Stange problem with sprintf or trace display
- Posted by AJ_Oxley Mar 13, 2012
- 1154 views
Thanks Greg,
I didn't think to handle the input as chars first before attempting arithmetic on the floating point.
That should work a treat!
11. Re: Stange problem with sprintf or trace display
- Posted by jimcbrown (admin) Mar 13, 2012
- 1157 views
I was somewhat surprised that a quick search in the archive didn't turn up any libraries that deal with money. I'm sure someone around here must have some code lying around.
Matt
There's a bignum or bigmath library that Lucius Hilley III wrote that can do arbiturary precision arthimetic.
The lack of a library specifically for money may be due to the ease of dealing with this issue simply by doing everything using integers and cents.