News for hackers. Stuff that matters.
Re:9999999999999999.0 – 9999999999999998.0 by lenticular on Saturday January 05, 2019 @12:17PM (#18832810)
Yeah, the limitations of FP are well-known to anyone who does much numerical work.

Floating point numbers are the optimal minimum message length method of representing reals with an improper Jeffery's prior distribution. A Jeffery's prior is a prior that is invariant under reparameterization, which is a mandatory property for approximating the reals.

In this case, it is where Prob(log(|x|)) is proportional to a constant.

Thus, we aren't going to ever do better than floats if we are programming on physical computers that exist in this universe. There is a reason why all numerical code uses them. Best to learn their limitations if you are going to use them, otherwise use arbitrary precision.

Re:9999999999999999.0 – 9999999999999998.0 by 3pt14159 on Saturday January 05, 2019 @07:08PM (#18835302)
Outside of the academic world decimals are almost always a better solution if performance isn't critical.

Most logic is multiplicative. For example, apply a 30% tax on a dollar quantity and display both subtotal and grand total. With floats, there are inequalities. With decimal there usually aren't unless you're dividing, but we already have to deal with divide errors in base ten, and it is much more likely to need to represent 0.30 than 1/3 and because decimal shares a base with binary (since it's factors are 5 and 2) binary doesn't really get us anything but headaches anyway. It's true that there are still gotchas, but they happen less often and usually don't end up looking stupid and weird for no reason. That 0.1 + 0.2 = 0.300000000000001 is dumb and we all know it.

Re:9999999999999999.0 – 9999999999999998.0 by jacobolus on Sunday January 06, 2019 @01:41AM (#18836954)
> Outside of the academic world decimals are almost always a better solution

Is “academic world” now a shorthand for “all numerical computing”?

Decimals basically never make sense, except possibly in some calculations related to money. Those make up a minuscule part of modern computer use.

Maybe decimals are also better for homework assignments for schoolchildren?

The type of applications where decimals are useful are by and large insensitive to compute speed and need no special hardware support. You can easily write your code for decimal arithmetic on top of integer arithmetic hardware.

Those of us who need binary floating point for graphics, audio, games, engineering, science, .... won’t stop you.

Re:9999999999999999.0 – 9999999999999998.0 by dotancohen on Sunday January 06, 2019 @08:47AM (#18838270)
Even with money I use integers. Instead of dollars (or local currency), I store values internally as pennies (or local equivalent 1/100 of main currency). Sometimes when working with interest I'll need to work with floats, and some databases I have values stored as DECIMAL(8,2) instead of INT, but for the most part I've saved quite a few headaches by keeping my values in INTs.
Re:9999999999999999.0 – 9999999999999998.0 by loa-in-backup on Tuesday January 08, 2019 @09:48AM (#18855799)
There are currencies that have the lowest value coin as 1/20 of main coin.
Re:9999999999999999.0 – 9999999999999998.0 by CamouflagedKiwi on Sunday January 06, 2019 @10:10AM (#18838675)
That seems okay until you need to track sub-penny accuracy somewhere, then you have a big problem.

Lots of applications don't need that, but a surprising amount do, so it's not a global solution.

Re:9999999999999999.0 – 9999999999999998.0 by hakfoo on Sunday January 06, 2019 @02:49PM (#18840171)
But there's still a minimum significant value which can be defined from the problem space. Do DECIMAL(16,8) or whatever.

In some situations, there may even be industry or legal standards as to what can be considered rounding noise.

Re:9999999999999999.0 – 9999999999999998.0 by toyg on Sunday January 06, 2019 @06:53AM (#18837874)
No need for snark. You might be correct that, by “computational volume”, handling currency values might be considered a niche; but even something like World of Warcraft has to handle money at some point.
Re:9999999999999999.0 – 9999999999999998.0 by nearbuy on Sunday January 06, 2019 @12:56AM (#18836819)
That doesn't seem dumb at all. Making BCD the default would mean floats use 17% more space for the same precision. That might seem like a small loss, but it's also for an incredibly small gain. Programmers would still have to be aware that testing two decimals for exact equality is dangerous. I don't see the problem with 0.1 + 0.2 = 0.300000000000001 if you aren't testing floats for direct equality.
Re:9999999999999999.0 – 9999999999999998.0 by otabdeveloper2 on Sunday January 06, 2019 @09:10AM (#18838371)
> it is much more likely to need to represent 0.30 than 1/3

Citation needed, because this isn't really true.

Even if one concedes your (unspoken) idea that only financial transactions aren't "academic" (which also isn't true), in the real world financial transactions will typically include currency conversions, and those will have all sorts of weird non-decimal factors.

Re:9999999999999999.0 – 9999999999999998.0 by ChrisLomont on Saturday January 05, 2019 @10:50PM (#18836450)
You cannot do anything in finance with such reasoning. Take something simple, say a mortgage at 5% compounded 12 times a year. To compute payments using some fixed length representation or decimal is going to lead to more error than to use the usual floating point. This rabbit hole would continue for many applications.

Floating point makes them all much easier to do well.

Re:9999999999999999.0 – 9999999999999998.0 by jes5199 on Saturday January 05, 2019 @11:08PM (#18836509)
Have you worked on finance software? I have - we always used ints for everything, so we could avoid rounding suprises
Re:9999999999999999.0 – 9999999999999998.0 by bigiain on Saturday January 05, 2019 @11:28PM (#18836578)
I did a web project in the gambling space ~10 years back - we were legally required to perform all calculations as integers in ten thousandths of a cent (or millionths of a dollar).

We chose to _not_ do _any_ calculations client side in Javascript...

Re:9999999999999999.0 – 9999999999999998.0 by dotancohen on Sunday January 06, 2019 @08:48AM (#18838274)
Which regulation is that? I've worked on financial applications, but not gambling, and I've not heard of this regulation. I should probably know about it!
Re:9999999999999999.0 – 9999999999999998.0 by bigiain on Sunday January 06, 2019 @05:18PM (#18841098)
Australian, or possibly Tasmanian state regs. This would have been around 2011 or so (The Samsung Galaxy S2 was the "top of the range Android phone" at the time...)
Re:9999999999999999.0 – 9999999999999998.0 by ajanuary on Sunday January 06, 2019 @10:59AM (#18838919)
I worked for a gambling company in the UK for a bit. They did all their maths in pennies, not thousandths of a penny.
Re:9999999999999999.0 – 9999999999999998.0 by ChrisLomont on Monday January 07, 2019 @04:17PM (#18850206)
Yes, I have. I also have a math PhD, have written scads of scientific and numerical software, and have written articles on floating-point math. So now that we have enough of our personal accolades out of the way, let's focus on facts regarding calculations:

How did you use ints to compute compounded interest on loans? I asked that above, and you avoided it. I ask again.

For example, suppose you have a mortgage where you lent $100K at 5% annual, compounded 12 times a year, for 30 years, and you need basic values regarding this loan.

Often in such calculations you need to compute 100K*(1+0.05/12)^360. How do you do that with integers? Naively you need (1+(1/20)/12)^360, which as a reduced fraction each of the numerator and denominator have over 2800 binary digits. Do you really do this with integers?

Now put that in a mortgage trading or pricing system where it needs to do millions/billions of those per second.

Doing this as double gives enough precision to make the difference between computed and infinitely precise negligible (approx. 10^-17 error).

It's easy to make examples where doing incremental calculations, rounding to pennies and storing, results in long term error. In these cases I don't see how do to it with integers without massive overhead.

And this is a trivial, common example. Doing stuff like hedge fund stuff, or anything using numerical integration to make models for pricing, would be astounding hardly to do with integer only math.

What finance software did you write? A simple ledger works fine as integers. Anything more complex will hit performance and scaling issues soon after the basics.

Re:9999999999999999.0 – 9999999999999998.0 by DougBTX on Sunday January 06, 2019 @09:01AM (#18838327)
I’ve not done any real finance programming, so is this a reasonable explanation?

Currency is stored as a count of cents (millicents if being fancy). Therefore the two main features of floats are not useful:

- Support for very small numbers is not needed. Floats dedicate approx half their range to numbers between -1 and +1, this is wasted when counting whole cents.

- Support for very large numbers at the expense of precision is actively bad, as the precision must always be down to individual cents.

So the useful range of floats is much reduced when using floats for counting, approx 54 bits out of a 64 bit float are used. Instead ints (“counting numbers”) are much better for counting cents than floats (which approximate the continuous real numbers in a finite number of bits).

Re:9999999999999999.0 – 9999999999999998.0 by shakna on Saturday January 05, 2019 @11:27PM (#18836571)
IBM Decimals are the standard for finance applications. Integers, not floating point.

Floats don't have the precision required.

Re:9999999999999999.0 – 9999999999999998.0 by erik_seaberg on Saturday January 05, 2019 @06:19PM (#18835010)
There's no reason for every step of a computation to be confined to the same very small message length. And the necessary error analysis should be built into the language, preferably in the same "advanced users only, here be dragons" package as the imprecise types themselves.
Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Saturday January 05, 2019 @06:30PM (#18835088)
So interestingly, processor makers are on the same page with you re: computations, and lots of processors can internally do computations in "extended precision", e.g. 80-bit floats, only converting to/from 64-bit doubles at the start and end of the computation.

https://en.m.wikipedia.org/wiki/Extended_precision

Re:9999999999999999.0 – 9999999999999998.0 by garmaine on Saturday January 05, 2019 @06:49PM (#18835207)
That hasn’t been the case for over a decade.
Re:9999999999999999.0 – 9999999999999998.0 by ealloc on Saturday January 05, 2019 @10:31PM (#18836388)
It may be coming back though.

IBM's new and rising supercomputer architecture, POWER9, supports hardware IEEE binary128 floats (quad precision). Their press claims the current fastest supercomputer in the world uses POWER9.

The ppc64 architecture (still produced by IBM) supports "double-double" precision for the long-double type, which is a bit hacky and software-defined, but has 106 bit mantissa.

And ARM's aarch64 architecture supports IEEE binary128 long-doubles as well, though it is implemented in software now (by compiler). Maybe they plan a hardware implementation in the future?

Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Saturday January 05, 2019 @07:08PM (#18835299)
How do you mean? The x86-64 instruction set / abi specifies long doubles as 80-bits, and still supports them ...
Re:9999999999999999.0 – 9999999999999998.0 by simonbyrne on Saturday January 05, 2019 @11:33PM (#18836597)
Essentially there are two different sets of floating point instructions on x86 and x86-64: - the x87 instructions, which descend from the original 8087 coprocessor (and have 80-bit registers), and - the SSE instructions, which descend from the Pentium MMX feature set, are faster, support SIMD operations, and can be fully pipelined.

The x87 instructions are basically for legacy compatibility, or if you manually use long doubles on some platforms.

The idea behind extended precision registers was good in theory, but ultimately caused too much hassle in practice.

Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Sunday January 06, 2019 @02:54AM (#18837180)
Yep - and there are absolutely some cases where you do want to manually use it which is why the x86_64 ABI on SysV (used by Linux and OS X, still specifies the long double type as 80-bits, and why GCC and Clang will still emit these instructions when long doubles are used!

(Sorry, this is more for the folks who aren't familiar with this, since it seems like you are familiar, but I didn't want it to seem like this isn't widely supported when they read "legacy" or "some platforms")

Here is a good toy examples that runs into the same numbers shown in the parent, showing the two different instruction types, and that long double can give you the correct answer, while still being run in hardware, vs. going all the way to float128s which are currently emulated in software!

Code w/ Assembly: https://godbolt.org/z/W3ZmqJ Output: https://onlinegdb.com/Sy_I3Q1ME

Re:9999999999999999.0 – 9999999999999998.0 by simonbyrne on Sunday January 06, 2019 @04:16PM (#18840764)
I agree that extended precision can be very useful, though I think the failing was on the software side: basically languages and compilers didn't provide useful constructs to control things like register spilling (which caused the truncation of the extended precision).

The current hardware trends seem to be providing instructions for compensated arithmetic, like FMA and "2sum" operations. I think this is ultimately a better solution, and will make it possible to give finer control of accuracy (though there will still be challenges on the software/language side of how to make use of them).

Re:9999999999999999.0 – 9999999999999998.0 by conistonwater on Saturday January 05, 2019 @08:48PM (#18835817)
All the floating-point arithmetic that is natively supported these days is the 32- and 64-bit kind in SSE instruction sets and its extensions. The fact that something is "available" doesn't mean much in terms of actual support. As far as I know, long double means 128-bit floats in modern clang/gcc, and they are done in software.
Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Sunday January 06, 2019 @12:38AM (#18836755)
Long doubles are typically 80-bit x87 "extended precision" doubles as far as I've seen. (Except on windows :-P ). It's part of the reason why LLVM has the 80 bit float type.

https://en.cppreference.com/w/cpp/language/types

https://software.intel.com/en-us/articles/size-of-long-integ...

They are definitely still supported in modern Intel processors. That said, there can be some confusion because they end up being padded to 16 bytes for alignment reasons, so take 128 bits of memory, but they are still only 10 byte types.

They are a distinct type from the "quad" precision float128 type, which is software emulated as you mentioned.

All that being said, you are right that most of the time float math ends up in SSE style instructions, but as soon as you add long doubles to the mix, the compiler will emit x87 style float instructions to gain the extra precision.

Example: https://godbolt.org/z/PMZVdb

Re:9999999999999999.0 – 9999999999999998.0 by leiroigh on Saturday January 05, 2019 @08:45PM (#18835800)
And nobody uses this terrible mis-feature in practice, everything runs via 64 bit xmm registers.

Rightly so, because programmers want their optimizing compiler to decide when to put a variable on the stack and when to elide a store/load cycle by keeping it in a register. With 80 bit precision, this makes a semantic difference and you end up in volatile hell.

Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Sunday January 06, 2019 @12:43AM (#18836772)
Yeah I agree that everything typically runs in XMM registers and that's what people want. I'm not sure what about the availability of extended precision makes it s a misfeature? For some cases it IS what you want, and it's nice to be able to opt in to using it..

EDIT: If I had some application where I needed the extended range, like maybe I was going to run into the exact numbers above, I'd appreciate the ability to opt-in to this. Totally agree I wouldn't want the compiler to surprise me with it, but also not terrible, or useless.

Code w/ Assembly: https://godbolt.org/z/W3ZmqJ Output: https://onlinegdb.com/Sy_I3Q1ME

Re:9999999999999999.0 – 9999999999999998.0 by BeeOnRope on Sunday January 06, 2019 @11:36AM (#18839085)
To be fair, the problem you describe isn't inherent to 80-bit floating point values. If you use 80-bit values in your ABI or language definition, it won't occur - it occurs when you try to user a wider type to implement a narrower type, e.g., implementing 64-bit floats (as specified in the ABI or language) with 80-bit operations.

In that case, the extra precision is present and "carried across" operation when registers or the dedicated floating point stack is used, but is discarded when values are stored to a narrower 64-bit location. So the problem is one really of mismatch between the language/ABI size and the supported hardware size. Of course, 80 bits isn't a popular floating point size any more in modern languages, so this happens a lot.

Re:9999999999999999.0 – 9999999999999998.0 by garmaine on Monday January 07, 2019 @06:57AM (#18844489)
The x87 ISA does, yes, and they are supported for binary compatibility reasons. However the actual x87 registers are shadowed by the vector registers so you can only use one. Any modern vectorizing compiler uses the vector instructions for FPU arithmetic, even when scalar, with a max precision of 64-bit.
Re:9999999999999999.0 – 9999999999999998.0 by gpderetta on Monday January 07, 2019 @07:45PM (#18851854)
>The x87 ISA does, yes, and they are supported for binary compatibility reasons.

Well x86-64 is not binary compatible with x86 so that's not the reason. It is mostly for software relying on either the rounding quirks or the extended 80 bit precision I guess.

> However the actual x87 registers are shadowed by the vector registers so you can only use one

You are confusing with the legacy MMX registers which are deader than the x87 for stack. XMM registers do not shadow the for stack.

Re:9999999999999999.0 – 9999999999999998.0 by loeg on Saturday January 05, 2019 @08:47PM (#18835812)
The x86-64 instruction set does not specify any particular ABI and definitely does not specify the precision of a C language type.
Re:9999999999999999.0 – 9999999999999998.0 by TFortunato on Sunday January 06, 2019 @01:03AM (#18836845)
Fair point, I was a little fast and loose with my words there, which is definitely dangerous when it comes to things like C language / ABI standards! :-P
Re:9999999999999999.0 – 9999999999999998.0 by lenticular on Saturday January 05, 2019 @09:32PM (#18836093)
A small message length means small memory, which is important in physical computers. It is information-theoretic optimal. This is a well-defined term.
Re:9999999999999999.0 – 9999999999999998.0 by erpellan on Sunday January 06, 2019 @04:13AM (#18837405)
The limitations should be well known. One of the first things I check when joining a financial software project is how the system represents money. I’m rarely surprised.

(It’s inevitably floats or doubles)

Re:9999999999999999.0 – 9999999999999998.0 by ayidnelm on Sunday January 06, 2019 @05:31PM (#18841164)
> Floating point numbers are the optimal minimum message length method of representing reals with an improper Jeffery's prior distribution.

Do you have a link to a proof or discussion of this? I haven't heard this before and I would love to have this statement unpacked a little more.

Re:9999999999999999.0 – 9999999999999998.0 by vanderZwan on Sunday January 06, 2019 @03:06AM (#18837216)
> Thus, we aren't going to ever do better than floats if we are programming on physical computers that exist in this universe.

Maybe, but that doesn't mean the particular implementation of floats being used is the best one. See also: Unums and Posits

https://posithub.org/

Re:9999999999999999.0 – 9999999999999998.0 by nestorD on Sunday January 06, 2019 @04:32AM (#18837444)
To my understanding, experiments with Unums showed shortcoming that Gustafson didn't anticipate and lead to Posits which drop the fixed length constraint. Doing that makes improving precision a lot easier but at the cost of computation time. Overall I am not convinced that the current implementation is optimal but it is a very good trade-off between speed and precision.
Re:9999999999999999.0 – 9999999999999998.0 by vanderZwan on Sunday January 06, 2019 @10:21AM (#18838733)
> Doing that makes improving precision a lot easier but at the cost of computation time.

Not quite. The difference in computation time is the current the lack of hardware support, not something inherent to the underlying encoding method. So in practice you are right, but in, for example, embedded contexts without floating point hardware, the performance advantages of IEEE floats should disappear (especially if using a 16 or 8 bit posit suffices).

Posits are simpler to implement than IEEE floats (less edge cases) and use more bits for actual numbers whereas IEEE floats waste about half on NaNs. The use of tapered precision is also nice.

Re:9999999999999999.0 – 9999999999999998.0 by tntn on Sunday January 06, 2019 @02:08PM (#18839965)
Even if hardware support existed, it seems like a variable length encoding has some inherent overhead relative to a fixed length encoding. If you have a "base length" of e.g. 32 bits and occasionally expand to 64, there's an inherent cost there in both computation and memory, presumably for greater precision. Perhaps that overhead could be minimal with hardware support, but it seems it must have some.
Re:9999999999999999.0 – 9999999999999998.0 by vanderZwan on Sunday January 06, 2019 @06:07PM (#18841333)
Those are type one unums, not posits. What you are saying about variable length encoding may be true, but it does not actually apply to the current comparison. Type 2 unums are also fixed length, but have other issues.
Re:9999999999999999.0 – 9999999999999998.0 by tntn on Sunday January 06, 2019 @06:47PM (#18841543)
'nestorD was discussing the effects and overheads of "dropping the fixed length constraint" in the comment you replied to.
Re:9999999999999999.0 – 9999999999999998.0 by vanderZwan on Monday January 07, 2019 @04:47AM (#18843983)
Oh darn, you're right. My bad!

In my defense, the comment he replied to got downvoted and I thought it was nestorD, so I was "primed" to misinterpret his comment as criticizing unums in general.