Live data from Hacker News

0.30000000000000004

0.30000000000000004.com

401–410 of 422 posts

Re: 0.30000000000000004

#401

MS Excel tries to be clever and disguise the most common places this is noticed. Give it =0.1+0.2-0.3 and it will see what you are trying to do and return 0. Give it anything slightly more complicated such as =(0.1+0.2-0.3) and this won't trip, in this example displaying 5.55112E-17 or similar.

Kahan (architect of IEEE 754) has a nice rant on it:

https://people.eecs.berkeley.edu/~wkahan/Mind1ess.pdf

(and plenty of other rants...:

https://people.eecs.berkeley.edu/~wkahan/ )

Re: 0.30000000000000004

#402
post #351
post #325

Earlier quoted context omitted.

That works for 10% of $21.15, giving the desired 212. However, for 10.14% of $21.15, it gives 215, but it should be 214. Another example is 3.5% of $60.70, for which it gives 213 but correct is 212.

You're right. My remainder calculation in my code snippet is incorrect. It should've been a floating point remainder instead. import math def tax_f5(amt, rate): t = amt * rate * 1000 return round(t) // 10 + ((math.fmod(t, 10.0) - 5.0) > -1e-7) But then since there's now an epsilon, it raises the question of how many digits of precision the tax rates typically need. This is indeed a difficult problem.

Some exhaustive testing on all amounts from $0.01 through $999.99 in $0.01 increments and all taxes from 0.01% through 99.99% in increments of 0.01% show that this is the minimum that does the trick (switching to C from Python for speed):

  unsigned long tax = (unsigned long)round(amt * rate * 1000000);
  return tax/(10000) + (fmod(tax, (double)(10000)) - (double)(5000) > -1e-5 ? 1 : 0);
(Yes, I see that I goofed in translation your code to C and typed -1e-5 instead of -1e-7. It looks like the results are the same with -1e-7).

I also tested that up through $9999.99 with taxes up to 12%, and no problems.

Adding another 0 to the 1000000, the two 10000's, and the 5000 works. And another, and another. Past that it starts to fail, but not the simple off-by-one failures you get when you don't use enough digits. These are way way off, so I'm guessing its running into some new class of problem. I haven't looked to see what that is yet.

Re: 0.30000000000000004

#403

Earlier quoted context omitted.

> When people talk about non-determinism of floating point, what they usually mean is non-associativity, that is (x+y)+z may not be exactly equal to x+(y+z). Good example of this, in Python 3: >>> (0.1 + 0.2) + 0.3 0.6000000000000001 >>> 0.1 + (0.2 + 0.3) 0.6

Every single time you run those two statements, you’ll get the same result. Yes they're non-associative. But that's specified and documented. That's not the same thing as non-deterministic in any way.

The same code might be optimised in different ways by different compilers, though (or the same compiler with different flags). This might lead to different results for the same code. In that sense, it's non-deterministic.

Re: 0.30000000000000004

#404
post #380

Earlier quoted context omitted.

False. Floating-point arithmetic in Java is generally nondeterministic. You will notice that the strictfp keyword exists and is off by default.

It's not false - strictfp mandates deterministic FP. If you use that your program will always run all floating point calculations in exactly the same way, full stop. Secondly, on mainstream implementations, strictfp is already documented the same as default! They're planning to remove it anyway as it's a no-op in almost all cases. See JEP 306.

> It's not false - strictfp mandates deterministic FP. If you use that your program will always run all floating point calculations in exactly the same way, full stop.

If you use it. Which is not the default. Your original claim remains false.

Re: 0.30000000000000004

#407
post #403

Earlier quoted context omitted.

Every single time you run those two statements, you’ll get the same result. Yes they're non-associative. But that's specified and documented. That's not the same thing as non-deterministic in any way.

The same code might be optimised in different ways by different compilers, though (or the same compiler with different flags). This might lead to different results for the same code. In that sense, it's non-deterministic.

> The same code might be optimised in different ways by different compilers, though

It's not an optimisation if it changes the result! And if you use non-standard flags that's your problem.

Re: 0.30000000000000004

#408

Earlier quoted context omitted.

Why doesn't everybody do it this way then? We would probably have a transparent built-in decimal type in every major language by now if there were no problems with this.

> Why doesn't everybody do it this way then? Why? Fintech uses decimal fixed-point all the way, there are libraries for them for any major language. Apps like GnuCash or ledger use them as well.

But Java has BigDecimal in its standard library and it's soooo slow I doubt it is implemented this way.

Re: 0.30000000000000004

#409
post #20

The big issue here is what you're going to use your numbers for. If you're going to do a lot of fast floating point operations for something like graphics or neural networks, these errors are fine. Speed is more important than exact accuracy. If you're handling money, or numbers representing some other real, important concern where accuracy matters, most likely any number you intend to show to the user as a number, f…

Decimal numbers are not conceptually any more or less exact than binary numbers. For example, you can't represent 1/3 exactly in decimal, just like you can't represent 1/5 exactly in binary. When handling money, we care about faithfully reproducing the human-centric quirks of decimal numbers , not "being more accurate". There's no reason in principle to regard a system that can't represent 1/3 as being fundamentally…

> Decimal numbers are not conceptually any more or less exact than binary numbers.

True but irrelevant. The problem isn't with the math fundamentals, it's the programmers.

The issue is if you get your integer handling wrong it usually stands out. Maybe that's because integers truncate rather than round, maybe it's because the program has to handle all those fractions of cents manually rather than letting the hardware do it so he has to think about it.

In any case integer code that works in unit tests usually continues to work, but floating point code passing all unit tests will be broken on some floating point implementations and not others. The reason is pretty obvious: floating point is inexact, but the implementations contain a ton of optimisations to hide that inexactness so it rarely raises it's ugly head.

When it does it's in the worst possible way. In a past day job I build cash registers and accounting systems. If you use floating point where exact results are required I can guarantee you your future self will be haunted by a never ending stream of phone calls from auditors telling you code that has worked solidly in thousands of installations over a decade can not add up. And god help you if you ever made the mistake of writing "if a == b" because you forgot a and b are floating point. Compiler writers should do us all a favour and not define == and != for floating point.

Back when I was doing this no complier implemented anything beyond 32 bit integer arithmetic, in fact there was no open source either. So you had to write a multi precision library and all expression evaluation had to be done using function calls. Despite floating point giving you hardware 56 bit arithmetic (which was enough), you were still better off using those clunky integers.

As others have said here: if you need exact results (and, yes currency is the most common use case), for the love of god do it using integers.

Re: 0.30000000000000004

#410

Earlier quoted context omitted.

ES does have an arbitrarily large integer type, BigInt. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Though the lack of support in IE, current Edge, and Safari, blocks that from client-side use for many. There are several BigInt libraries out there that you could use, though obviously this is not as convenient and even if they wrap BigInt when available will be less efficient.

Latest Edge dev preview has supported it since the switch to Chromium. The Chromium-based Edge launches on Jan 15th, at which point Edge will support it.

Safari (WebKit) actually has a fully working implementation, they just haven't shipped it yet. Search the release notes for "BigInt": https://developer.apple.com/safari/technology-preview/releas...

Post reply on HN