"If you want a default decimal floating-point type, the only defensible choice is the decimal128 type standardized by IEEE 754. It has a fully-defined arithmetic, specified by experts who have spent their careers thinking about the issues involved, and is wide enough to exactly represent the US national debt in every currency used on earth.
There are situations where other decimal floating-point types are appropriate, but if you do not understand the tradeoffs you are making, you should be using decimal128."
and
"I would be remiss not to note that Intel has made available a well-tested complete implementation of IEEE 754 decimal64 and decimal128 under 3-clause BSD: http://www.netlib.org/misc/intel/ "
Can’t you link the existing C code by Intel, linked above and BSD licensed? There’s also GPL licensed one by IBM if you prefer that, linked in my other post.
No need to use the worse solution, which is dec64, unless you have some very specific goals.
"A later revision of IEEE 754 attempted to remedy this, but the formats it recommended were so inefficient that it has not found much acceptance. DEC64 is a better alternative."
This is just plain wrong. The IEEE decimal float types are now in SQL as DECFLOAT, coming to C and C++, I could go on...
Seems useful to me. Fixed sized data is very convenient for computers (fits in a register, pass-by-value), and being able to represent 0.1 and 0.01 is very convenient for humans.
The hardware does seem to be of questionable value; I heard rumours that the POWER hardware didn't actually beat the Intel software implementation running on an x86. That doesn't mean that the datatype is worthless.
And it sure as hell doesn't mean that this DEC64 type, which has arbitrarily incompatible parameters but adds nothing, and is late to the game, is better!
This looks absolutely beautiful (from a computer scientist, mathematician's and aestheticist's perspective)... Future typed programming languages should include this type!
Unfortunately this website doesn't talk much about the shortcomings of DEC64. Just to start, numbers in DEC64 have multiple representations, meaning even a simple equality check can take tens of cycles. Don't get me wrong, it's a cool way to store numbers, and it does have purpose, but it is not suited for general use like IEEE754 is.
I checked out the reference implementation and although there are some heuristics to make comparing numbers faster, you're completely right that the worst case scenario is quite complicated: https://github.com/douglascrockford/DEC64/blob/master/dec64....
That code is certainly not written by someone with x86 optimization experience. Using high-byte registers (e.g. ah which he rewrites as r0_h) is an awful idea on any Pentium Pro or more recent processor.
IEEE754 also has multiple representations along with imprecise representations of integers, it’s limits (+Inf, -Inf, NaN) and simple decimals (0.1 + 0.2 != 0.3). For now, the biggest benefit is that we have hardware acceleration for IEEE754 everywhere, not that it is particularly good for any use case or that it is without weakness. But when we get FPGAs in commodity CPUs, the pros and cons value of IEEE754 change rapidly. Custom arithmetic formats could become more common.
nan != nan severely bothers me, when it's the same object on both sides with exactly the same bit pattern. It's the work of imbeciles who are either unfamiliar with the concept of identity, or else don't understand why it's important and should be respected.
It feels like an argument between useful and correct.
Correct is "These two items are not numbers, so the numeric concept of equality can't be conclusively applied." This argument gives you NaN != NaN.
Useful is "We consider everything that's escaped the plane of numbers to be equivalent because they all require the same special handling." This gives you Nan = NaN.
Problem is, there are multiple representations identified as "NaN". The question whether one NaN should be considered equal to another NaN is different from whether a NaN should equal to itself.
Whether a NaN is equal to a different NaN depends on the kind of equality; some equalities don't care about certain differences.
The C == equality allows the integer 1 to equal 1.0, in spite of a different representation; it is not simply a bitwise equality. (This happens by way of conversion of 1 to 1.0).
However, a thing should equal to itself under every applicable equality. That is non-negotiable.
There is a sense in which eq(x, x) can be false, if we consider argument passing to work by copy, and argument position to be part of identity. Then x is not x, because one is the left x and one is the right x they are in different stack locations or machine registers or whatever. Common Lisp allows for this kind of chicanery in its definition of "implementation identity" (embodied in its eq function). Numbers are not required to be eq, even to themselves. (eq 0 0) could yield false, the idea being that each copy of 0 could be a distinct object. Though that sort of stinks, it's not what is at pay here. These NaNs have type double, and ordinary values of that type are equal to themselves when copied to different argument positions of the equality operation.
This is true, but hardly important. Multiple representations hurt because they waste space, not because they're transiently evil.
If you're scared of normalizing before comparisons, or somesuch, nothing stops you normalizing around operations instead, like standard binary floats. Only you'd probably be shooting yourself in the foot, since you'd probably end up normalizing more and making the ‘integers are fast’ claim fail.
No. Except for being decimal (and incidentally not implemented in most if not many architectures) it shares the same shortcoming with binary floating point numbers. [1]
[1] Note that this comment also applies to IEEE 754 decimal fp.
This seems similar to the c#/ .net decimal type (1), except the .net type is 128 bits. The c# decimal precedes the IEEE decimal types and isn't the same.
LNS doesn’t seem to meet either of the goals of DEC64:
- Drop-in replacement for signed integer types for loop iteration, array indexes, etc (Exact integer operations for 56 (55?) bit addition and subtraction with 1 cycle overhead; similar efficiency for multiplication)
-Drop in replacement for financial fixed point types (which need to be exact in base-10)
Essentially just a base-10 version of floating point. It will work better for accountants and others performing conventional math done with base 10, but no fundamental advantage. The problem stems from trying to represent an uncountably infinite set with a finite set -- at the end of the day you end of with a very sparse approximation.
Dismissing it as "better for accountants" feels trivializes the problem.
There's billions of lines of code in circulation dealing with fixed-decimal currency formats.
The choices have always been:
* Scale things up and down (do your math in cents and convert back to dollars at the last minute), which is an easy opportunity for off-by-2-orders-of-magnitude bugs
* Use floating points and pray nobody notices the all but guaranteed errors
* Use something like BCD and have to explain it to everyone
* Deal with some custom format or language-specific type, kissing portability goodbye, and depending on implementation, possibly poor performance
A well-established decimal-friendly type, whether this, decimal128, or something else, provides a go-to solution to a very common problem.
BCD has been around since the earliest CPU's. I get the importance of using base 10 for finances, but there is nothing new offered here that I can see.