- Feature Articles
- CodeSOD
- 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
You meant "binary floating-point" (at least I hope say), but you used "float". The type float generally has only 24 bit precision, and a rather limited range, while the type double has 53 bits of precision (more than 8 decimal digits more) and a much wider ange of values, so using float instead of double is asking for trouble. And without any need.
Admin
There is a big mistake made here. And that mistake is to only show examples where for some reason decimal numbers give the desired result, where binary floating point doesn't. But take $100 and divide by 3, then take the result and multiply by 3. Decimal won't give you the desired result either.
What everyone is missing is that financial calculations are usually governed by rules. There will be rules in place that specify whether a result that would mathematically (with infinite precision) be 14.375 should end up as 14.37 or 14.38 or either. These rules have to be written down and followed.
Maybe the rule is "the calculation should be done as if with infinite precision, and then rounded to two decimal digits, rounding to an even last digit for values precisely between two possible values (in other words: 14.38). That's easily achieved in double precision; you figure out from the input values that the exact result would be a number with say 7 decimal places followed by zeroes. That means if your calculated result is 14.374,999,981 then the true result must be 14.375,000,0 and gets rounded accordingly. A little bit of maths, but you write a function for it once.
If the rules are different (for example, if you buy n items for x pound each, then n times x is calculated, rounded to two decimal digits, then multiplied by 0.2 and again rounded to 2 decimal digits for VAT, then that's what you implement.
Whether you use double or decimal internally will affect your code that you use to implement the rules, but must never influence the outcome.
Admin
As one of my instructors used to put it, "Engineers are superior to accountants because they are allowed to add, multiply, divide and subtract. Accountants are only allowed to add and subtract, if they divide or multiply they get sent to prison."
Admin
:shooting_self_in_head:
Admin
There most definitely is a need.
The vast majority of scientific/technical computing is done with single-precision, which is what you would use if we're talking about a stock price model. Saturation is what ruins your calculations because it hits it with a huge non-linearity. Single precision is good for 1 in 100,000 to 1 in a billion, and shows up as minor, distributed noise component.
Take the latest nVidia GPUs, double is 3 times slower. Of course, double takes up twice the RAM, cache, bandwidth etc.
Admin
How do we know this (silly) code is modeling currency? Could it not be modeling the second stage LOX tank pressure in a rocket?
Admin
we don't. not in the case of the article.
however @loose explicitly mentioned currency conversion in his post that i was directly replying to.
I know in his example that we are dealing with currency and thus my reply.
;-)
Admin
Nope, can't do it with double precision. What's 64.01 * 100000000000002, to the nearest integer? You can't get the correct answer of 6401000000000128 with only 53 bits of mantissa (you'd instead get 6401000000000128.53... and incorrectly round up to 6401000000000129).
Just use a decimal or integer type. End of story.
Admin
He should have used a libary.
Admin
Perhaps mentioning multi-currency was a "bridge too far", it was only included to illustrate the complexity of the issue that the Dev had. The real point was that the Dev had to find another method of accurately calculating the VAT, that could be (and anecdotal evidence seems to suggest that it would be considered :wtf: Code.
As I stated, and as has been independently pointed out, there are times when you have to bite the bullet and just do it.
That aside, and I really am pissing myself with laugher here, currency conversion was not done adhoc because any minor inaccuracies due to rounding errors paled into insignificance. because of fluctuations in exchange rate. The prices were uploaded once every 24 hours from the Accounts Package and the decision was made and go with the "get out of jail free" card of a caveat and leave it at that
Admin
This.
And This.
To state the obvious (as I'm in a pe<bold>n</bold>dantic mood today), the WTF is float to double conversion "via a string". Whether the WTF is because of the dev or the language, or some $deity-awful laws that need to be complied with, I get a
FILE_NOT_FOUND
error.
Filed under: Probably some stupid law causing this. When in doubt, blame the government.
Admin
This may be irrelevant, but I was talking to a bank programmer the other day and he remarked that they still have to handle an awful lot of data in csv format, because they get sent exported data which may have huge numbers of tuples and any other format takes up more space. To quote Marvin, it sounds truly awful.
Reading csv files from various sources is a PITA - everybody has their own notion of how they need to work - and sooner or later you are going to have to work around some wtf which involves string to number conversion. I don't suppose this is the case here, but in the past I have had to have custom string to number and number to string formatters to import from, process and export to csv files.
Admin
If you are getting numbers like that in your accounting system, either something is very wrong or the Greek government would like a contribution from your petty cash drawer to pay back their debt and rebuild their economy.
Unless we get hyperinflation any time soon, any example using numbers > 1012 is just looking for an argument.
Admin
US national debt > 1.8 * 1013
Admin
If your accounting system (the context I was referring to) is regularly handling the US national debt as a number on which it does multiplicative arithmetic, I'm glad I don't work for your company. Even Apple has a turnover < $1012, though I guess if the bubble doesn't burst that might get exceeded one day. But that's going to be the biggest number in the annual statement, and nobody is going to worry about the rounding error in the last place.
Admin
My example was clearly artificial, and I agree that numbers that large aren't going to show up in any real accounting situation for the next few decades. But using "53 bits of precision should be enough for any data this software will ever process" as an excuse to write buggy software is still wrong, especially when the correct alternative is clear and usable. Every language you might possibly write new code in this days has a reasonable Decimal/BigDecimal implementation in it.
"640k should be enough for everyone", right?
Admin
Not disputing the WTF'ery. Just the target selection for the dope slap needs to be investigated.
Admin
Am I missing something here? Assuming Java's Float.toString method will return the entire float and not perform any rounding or truncation, and assuming that Double.parseDouble correctly converts whatever format Float.toString returns back into an equivalent double, wouldn't this code be entirely unnecessary?
Basically: wouldn't typecasting from float to double accomplish the exact same thing? Or is the author taking advantage of some not-very-clear behavior of Float.toString that may perhaps lose precision in the process of going from float to String?
Admin
Replying to @nlaq and @everybody en passant
Is it just me, or has something been missed here?
From the Article:
" Because the model use doubles in calculations while the matrices holds floats."
It's a while since I have used Java but, whilst it won't produce fireworks, taking a Float and treating as a Double could cause some interesting, unforeseen consequences. Apparently a goggle at "java float to double conversion issues" gets nearly 1/2 million hits.
Surprisingly the code in the Article, and the "toString" Method (as well as the "BigDecimal" Class) are offered as (possibly Official) solutions.
Now, I did not know this in any detail until I actually researched it, but that don't alter the fact that my "spidey sense" (Nod to @wesley_long) could be right.
Admin
Yes, perfectly true. My point was simply that in reality and for accounting applications, 64 bit precision isn't the problem (which may be why they continue to do it.) The problem is how the underlying code handles numbers around 0.5 and 0.005, and is due to our completely artificial concept of rounding - which has just led to the English Appeal Court deciding that "1%" includes 0.5...........1%, insert as many zeroes as you like. I hope that goes to the Supreme Court and a few statisticians are allowed to testify.
Admin
And virtually every one of those is because someone is an idiot. For example:
http://stackoverflow.com/questions/916081/convert-float-to-double-without-losing-precision
The answer to that is very good indeed; the actual problem in the original code is that the input data was never precisely transcribed into a
float
in the first place.In reality, each floating point number actually represents an interval of real values. The value that you get when you print one out is just a representative of that interval. Most programming languages have pretty nasty float-to-string conversion routines actually, and it turns out that it's really very difficult to get “right” (where “right” means “converted to the representative of the interval that has the fewest necessary significant digits”).
If you want to read up on the sorts of things you need to know to do that conversion right, you probably need to do some academic literature searching:
And for test vectors:
Yes, that's heavy going. I don't know of many languages that get it right by default. I do know of one… :smile:
Admin
Ummmm, all you say is true, but: a) Nothing to do with the article, and b) Anybody reading TDWTF will already know about representing money. Your 'wisdom' is mostly just TLDR.
Fact: A double precision float can exactly represent any number that can be represented by a single precision float. ANY number.
Nothing done by this function solves any problem. The return value is a binary fraction so it doesn't matter how you round it inside the function it can never return a 'more accurate' value. It can only return a wrong value.
Binary fractions simply can't exactly represent decimal fractions, decimal fractions can't represent numbers like one third. It's simple math and shouldn't surprise anybody (or need any prolonged explanation).
Admin
Or maybe you started reading the comments on the main page: [image] I was confused too until I read the full comment here...
Admin
Interesting Bug, or is it a Discourse design feature to encourage discourse?
Admin
Because of this, you are all pardoned for your transgressions. So I won't be making the Post I had planned to :)
Admin
Zimbabwe got to the point where the ATM's couldn't dispense a bill big enough to buy anything. They at one point issued Z$100,000,000,000,000 notes.
They redenominated again, and then.... just gave up. The Z$ won't be legal tender after this year.
Admin
I had to fix a bug in our code that produced one in one part and the other in another part. From memory it was a combination of discounts and tax that produced an "exact" $x.xx5 but different code handled this case differently so it was a cent out between the product page and checking out. A simple
sprintf("%.2f")
was not enough. It was worse because this item was generally bought in bulk so an order was often dollars incorrect. Changing it so the everywhere calls the same rounding function was the fix.Admin
People keep putting up these examples...somehow I doubt anybody is going to design an accounting system purely to deal with R. Mugabe's
fascist dictatorshipunusual state arrangements. Certainly not if they're going to be paid in his currency.Admin
I think they are on the ear standard atm. You know 1 ear = head, 1 head = 1 less body. 2 ears nullifies the current transaction because it is a blatant and fraudulent attempt to double your income.
Admin
Apparently, nobody actually read the code. If they did, they'd see that calling the function already cast the double to float making the string conversion even more convoluted and useless. So the string conversion part is converting a float back to double then to string then to float!