• (disco) in reply to safarty

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.

• (disco) in reply to Khudzlin

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.

• (disco) in reply to loose
loose:
Please, I have only just gotten out of therapy over this sort of thing.

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."

• (disco)

• (disco) in reply to gnasher729
gnasher729:
so using float instead of double is asking for trouble. And without any need.

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.

• (disco) in reply to accalia

How do we know this (silly) code is modeling currency? Could it not be modeling the second stage LOX tank pressure in a rocket?

• (disco) in reply to JimNtexas

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.

loose:
Once upon a time there was a certain version of a certain programming language that was used for a multi-currency e-commerce site.

I know in his example that we are dealing with currency and thus my reply.

;-)

• (disco) in reply to gnasher729
gnasher729:
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.

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.

• (disco)

He should have used a libary.

• (disco) in reply to accalia

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

• (disco) in reply to dkf
dkf:
Rounding might be important sometimes, but going from float to double via a string is not a winning proposition, especially as the precision of the conversion to string isn't specified.

This.

Wesley_Long:
I'd need to see more context. From the comments, it almost comes off as sarcastic, passive-aggressive parroting. My "Spidey Sense" is telling me that the dev was forced to do this, and isn't happy about it.

Again, would need to see more from this dev to get a good read on it.

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.

• (disco)

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.

• (disco) in reply to Protoman
Protoman:
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).

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.

• (disco) in reply to kupfernigk
kupfernigk:
any example using numbers > 1012 is just looking for an argument.

US national debt > 1.8 * 1013

• (disco) in reply to HardwareGeek
HardwareGeek:
US national debt > 1.8 * 1013

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.

• (disco) in reply to kupfernigk
kupfernigk:
Unless we get hyperinflation any time soon, any example using numbers > 1012 is just looking for an argument.

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?

• (disco) in reply to Wesley_Long

Not disputing the WTF'ery. Just the target selection for the dope slap needs to be investigated.

• (disco) in reply to loose

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?

• (disco) in reply to nlaq

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.

• (disco) in reply to Protoman
Protoman:
Every language you might possibly write new code in this days has a reasonable Decimal/BigDecimal implementation in it.

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.

• (disco) in reply to loose
loose:
Apparently a goggle at "java float to double conversion issues" gets nearly 1/2 million hits.

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:

William D. Clinger, How to Read Floating Point Numbers Accurately, Proceedings of the ACM Conference on Programming Language Design and Implementation, June 20-22 1990, pp. 92-101. http://citeseer.nj.nec.com/clinger90how.html

Guy L. Steele Jr. and Jon L. White, How to print floating-point numbers accurately. In Proceedings of the ACM Conference on Programming Language Design and Implementation, June 20-22 1990, pp. 112-126. http://doi.acm.org/10.1145/93542.93559

David M. Gay, Correctly rounded binary-decimal and decimal-binary conversions, Numerical Analysis Manuscript 90-10, AT&T Bell Laboratories, Murray Hill, New Jersey, November 1990. http://citeseer.nj.nec.com/gay90correctly.html

Robert G. Burger and R. Kent Dybvig, Printing Floating-Point Numbers Quickly and Accurately, SIGPLAN Conf. on Programming Language Design and Implementation, 1996, pp. 108-116. http://citeseer.ist.psu.edu/28233.html

And for test vectors:

Brigitte Verdonk, Annie Cuyt, Dennis Verschaeren, A precision and range independent tool for testing floating-point arithmetic II: Conversions, ACM Transactions on Mathematical Software 27:2 (March 2001), pp. 119-140. http://citeseer.nj.nec.com/verdonk99precision.html

Yes, that's heavy going. I don't know of many languages that get it right by default. I do know of one… :smile:

• (disco) in reply to loose

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).

• (disco) in reply to ashkante
ashkante:
Ah, so it was my reading comprehension that threw a cog.

Or maybe you started reading the comments on the main page: [image] I was confused too until I read the full comment here...

• (disco) in reply to dahaka

Interesting Bug, or is it a Discourse design feature to encourage discourse?

• (disco) in reply to loose

Because of this, you are all pardoned for your transgressions. So I won't be making the Post I had planned to :)

• (disco) in reply to kupfernigk
kupfernigk:
Unless we get **hyperinflation** any time soon, any example using numbers > 1012(Oh look a bug) is just looking for an argument.

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.

• (disco) in reply to gnasher729
gnasher729:
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.

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.

• (disco) in reply to ijij
ijij:
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.

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 dictatorship unusual state arrangements. Certainly not if they're going to be paid in his currency.

• (disco) in reply to kupfernigk

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.