- Feature Articles
-
CodeSOD
- Most Recent Articles
- What a More And
- Hall of Mirrors
- Magical Bytes
- Contact Us
- Plugin Acrobatics
- Recursive Search
- Objectified
- Secondary Waits
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
I gotta figure 64 bit architectures with m atching date libraries will be ubiquitous by then. Then again, the Cobol stuff written in 1960 will probably still be running, so who knows ;)
Admin
sh*t, just use the 'money' or 'decimal' type for the data. Or whatever your database provides to get round the FP/decimal problem. If your database only provides floats - get a proper one!
Admin
In a previous job we stored all money in thousandths of a penny (0.001 cents) when dealing code-side (Java BigDecimal and BigInteger). In the database it was stored using the MS money type (4 decimals). The industry was gambling so you can be assured that if money that disappears end up with people in worse places than the US ClubFed (considering we sold to Latin America and Eastern Bloc countries).
The reason was is that our cash register/terminal had to take in money from several different currencies (Bolivars, US Dollars, Euros, Rubles, Mexican Pesos, Yen, etc.) convert that to USD to purchase against a US Company - often within the same purchaing transaction (say 10.50 USD + 350 PEN). All winnings were in USD and payouts would be in USD or EUR.
At the end of the day we had to balance our drawer. The final amount was based upon what we owned the US Company (only available in US Pennies), plus any extras tacked on by the company taking the money (held in our database), plus a small fractional file that kept millionths of pennies lost or gained during each transaction so that the drawer would balance out.
I'm the decider
Admin
Actually, "08" is a string.
Not in the language that I posted in (English). '"08"' is a respresentation of a C string constant. "08" is the quoting of two characters.
Sincerely,
Gene Wirchenko
Admin
Let's hear it for languages that support a BCD datatype. It's perfect for dollar amounts.
Admin
Patterns of Enterprise Application Acrhitecture says that you should indeed treat money as integral numbers of the smallest unit (pennies). This is to ensure that you don't lose pennies to rounding errors, etc.
Admin
Patterns of Enterprise Application Acrhitecture is talking out of its ass.
Admin
No, CAST(expression AS type) doesn't bind that way.
CAST(x * 0.0115 AS INT) is interpreted as
CAST( (x * 0.0115) AS INT)
not CAST(x * (0.0115 AS INT) ), which would be a syntax error.
Admin
Task: add a 15-percent fee.
Required: to know the precision of the inputs, the precision of the datatypes, the idosyncracies of the programming language (and the compiler!), etc. For example, does 1 + .15 equal .15 + 1 ? (Some languages yes, some no.) When does the compiler perform implied datatype conversions for me, and what does it do about precision? (e.g. trying to compare a float and an int) If I perform the identical calculation multiple times in the code, will the compiler re-use the previous result, or will it re-do the calculation? Does the treatment of negative numbers match my requirements?
For today's WTF, we also need to understand the storage space implications: if a datatype were twice as big, it'll take up twice the space, take twice as long to back up, etc. Sometimes, that's a problem.
Admin
After some battles with accounting types I've become a firm believer in storing money as pennies. Note that the 4-fixed-place currency types are NOT suitable if you plan to do any multiplicaiton (say, percents) with them. The problem with them is that you can get fractional pennies that end up adding up to more than a penny. So long as there is only one way to calculate something this doesn't cause a problem so long as you apply the percents as late as possible--the guy checking the math with a calculator will do the same thing. However, what if there is a detail mode where the percentages must be applied line by line?
Admin
pennies += pennies*3/20;
Admin
And you are... ?
Admin
Yeah, but in Analysis Patterns (http://martinfowler.com/ap2/quantity.html), he uses BigInteger and says:
Admin
Why? Integer arithmetic is exact; floating-point arithmetic is not. Given that rather innocuous and common decimal values such as 0.1 and 0.7 cannot be represented exactly as binary fractions, you're going to run into rounding errors pretty quickly, and the more operations you perform, the more the error propagates into the higher-order bits. Losing or gaining a cent here and there may not sound like a big deal at first, but when you're talking about hundreds of thousands to millions of transactions a day, it winds up being enough money to worry about.
Admin
1000 gallons of gas sold at $3.199. What's the total revenue?
Two $1.00 sales taxed at 8.5%. How much tax do you owe?
Sure, you can say "Add up everything before multiplying." But then each application has to be specially written so that it does operations in the right order, and the accountants won't have the numbers that they want. Decimal types really are the Right Thing.
Admin
Well in Australia we'd calculate the GST on the sum of the taxable transactions, not the sum of the tax on the individual transactions. Which makes the calculation pretty easy.
Admin
It's doesn't matter as 0.1 can be represented with an error less than 0.000000001, which, to all extent, rounding properly, is enough. Of course you could use double instead of float. Then the value is represented EXACTLY. In fact, every number using only two decimal can be represented EXACTLY. Humm seems to be enough for banking... but that's noto all, is exact until
As you've said, if you give a good precission, let's say till decimal place 10,... get conclusions on your own.
It works, but hey, you are all right, floating point numbers and standard IEEE 754 are only entertainments made by people who had absolutely no idea, and had nothing more interesting to do. Of course, altough you are probably a not very skilled programmer but with a head full of yourself, you are probably right and people using floating point have no idea what they're doing.
What is really worth to laugh at, is the fact that, altough banking needs to make high precission calculations, decimal places involved are a few, so no problem with proper understanding of what's going on. But instead of reading, it's better falling into the realm of the arcane an say it's preferably to use integer for decimal fixed point calculations. I would understand fixed point if the language provide such, and you had nothing more to do, as Ada does for example, but if you have to implement something else, floating point is not only enough, but very enough. And the frightened it's me, as it is this kind of thinking ("humm i know more than anyone so let's reinvent the wheel in a squared fashion") that leads to misinformation later, and arcane thinking of how are things.
Admin
No, it isn't. Values like 0.1 cannot be represented exactly as a binary fraction, period. You get a helluva lot closer with a double as opposed to a float, but it's still not exact.
The problem is not whether you can represent a single number to within a given precision; the problem is that because the values aren't exact, every operation introduces some roundoff error, and those errors accumulate. After doing enough transactions, the error becomes significant.
For example, take this innocuous little loop:
float sum=0.0; for (i = 0; i < 10000000; i++) { sum += 0.1; }
The result should be 1000000.00000, right? After all, 0.1 is accurate enough to within a bunch of decimal places, right? Well, after running this, the result I get is 1087937.0000000. Typing sum as double does help a bit: then I get 999999.9998390.
IEEE 754 is good for what it does, but when you're processing hundreds of thousands to millions of transactions a day, and your results have to be accurate to the penny (or even fractions of a penny), then "good enough" isn't good enough.
Admin
God DAMN it, I hate IE-centric sites!!!
Let's try this again:
float sum = 0.0; for (i = 0; i < 10000000; i++) { sum += 0.1; }
Expected result: 1000000.0000000 Actual result: 1087937.0000000
Typing sum as double: 999999.9998390
Again, the problem isn't representing individual values; the problem is accumulation of error over a large number of transactions.
Admin
Seems you are using VC++ compiling for Debug... use Release...
Don't think there will be ten million pennies getting added anywhere... but you never know [:D]
Admin
gcc, not VC++, and that was a release target (not that it would make a difference).
Again, the point is inexact numbers + large number of transactions = significant error in results.
And do you think we could have a slightly longer timeout for captcha validation?
Admin
In fact it does...because of code generated, but dependes entirely on your compiler...
Admin
Also if you need to query by date range and you code something like
WHERE somecol BETWEEN 20051201 AND 20060101
the optimizer will think there are 8,900 days in the range. That kind of thing can really mess with your execution plans.
Admin
Which just argues even further against using floating-point types for financial calculations; if the result you get depends on the build environment, then you have real problems.
But, okay, I built it under VC++, in release mode, and I got the result 999999.999839. Changing the constant to 0.1f gives the result 1000000.014901.
Good enough for government work? Not quite.
Admin
So, under the system you propose, 100 washers costing $2.49 yields pennies = 249, right? So what's the cost of a washer? Of course you ignored that part of the poster's reply. Here's a hint 249/100 w/ int division is 2. But each washer doesn't really cost 2 pennies, does it? It costs about two and a half pennies.
Admin
Of course fractions (of limited length) can be exactly represented in binary. 0.07 (dec) = 0.0001001(bin) 8-|
Or what did you mean ?
Admin
Some people do not appear to know what "exactly" means. Valuable Clue: It does not mean "approximately". 0.0001001 base 2 = 9/128 = 0.0703125. This is not exactly 0.07, is it?
Sincerely,
Gene Wirchenko
Admin
Which is why you pick a scale appropriate to the problem. In this case, you're dealing with hundredths of pennies. $2.49 == 24900 hundredths of pennies. So 1 washer costs 249 hundredths of cents.
The drawback to this is that you can't just naively use a native int or long datatype; at that fine a scale, the largest dollar amount you can represent in a 16-bit int is $6.53 + 36/100.
Admin
18446744073709551615 ulong max
0,1087937
0,0999999999838975
0,1000000000000000000000000001</FONT>
Admin
There should be no taxes (whatsoever) on 1c individual charges. Taxes are computed as the applicable percentage against the aggregate of items at the given tax rate/code. This is why I shudder when I see tax fields in line details (e.g. items in invoices) rather than in the header (or a separate tax summary).
Integers are better than unconstrained real/floats. But is there a presupposed 2 decimals - lots of telco land transactions are required to 5 decimals with rounding to cent values at appropriate aggregation points. E.g. transactions for interconnect/roaming charges denominated in XDR.
And if you use integers what do you do with non-decimalised currencies such as HUF? Do these get multiplied by 100?
Life ain't simple. I would fire the programmer who wrote the original code on the spot. He/she is destined to a special career in comedy.
Admin
<FONT face=Arial>I wish this classic paper was made mandatory reading for every computer science student:</FONT>
<FONT color=#003366><FONT face=Arial></FONT><FONT face=Arial>What Every Computer Scientist Should Know About Floating-Point Arithmetic</FONT></FONT>
<FONT face=Arial>I myself would have saved a couple of months extra work converting doubles to longs in my first 'real job'. (Nothing to do with money, though. It was a desktop-publishing sort of application, computing areas and such.)</FONT>
Admin
Don't see the mind set? Have you ever worked with BASIC in the 1960's? What were the data types like in some of the "Open Source" mini-BASICs for the 8080, 8008 and Z-80? Integers and strings!
I am also trying to figure out why they used FLOAT for money calculations instead of following EU and GAAP rules.
Or how you write a constraint for the dates to keep them valid. Oh yeah!
Admin
Most retailers handle this sort of thing by having a separate entry on each line item that contains the taxable amount of the line item. The reason for this is that there's plenty of customers that can buy certain items tax-free, depending on local laws and such. And this can vary customer to customer. So you keep the taxable amount of each line item (which you usually look up in some form of table), then charge taxes on that total instead of the actual total. This makes things work.