Live data from Hacker News

0.30000000000000004

0.30000000000000004.com

151–160 of 422 posts

Re: 0.30000000000000004

#151
post #2

This is a good thing to be aware of. Also the "field" of floating point numbers is not commutative†, (can run on JS console:) x=0;for (let i=0; i --> 1.000000000000001 x=1;for (let i=0; i --> 1 Although most of the time a+b===b+a can be relied on. And for most of the stuff we do on the web it's fine!†† † edit: Please s/commutative/associative/, thanks for the comments below. †† edit: that's wrong! Replace with (a+b)+…

Note that the addition is commutative [1], i.e. a+b==b+a always. What is failing is associativity, i.e. (a+b)+c==a+(b+c) For example (.0000000000000001 + .0000000000000001 ) + 1.0 --> 1.0000000000000002 .0000000000000001 + (.0000000000000001 + 1.0) --> 1.0 In your example, you are mixing both properties, (.0000000000000001 + .0000000000000001) + 1.0 --> 1.0000000000000002 (1.0 + .0000000000000001) + .0000000000000001…

I tried to determine how to perform IEEE 754 addition (in order to see whether it's commutative) by reading the standard: https://sci-hub.tw/10.1109/IEEESTD.2019.8766229

(Well, it's a big document. I searched for the string "addition", which occurs just 41 times.)

I failed, but I believe I can show that the standard requires addition to be commutative in all cases:

1. "Clause 5 of this standard specifies the result of a single arithmetic operation." (§10.1)

2. "All conforming implementations of this standard shall provide the operations listed in this clause for all supported arithmetic formats, except as stated below. Unless otherwise specified, each of the computational operations specified by this standard that returns a numeric result shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that intermediate result, if necessary, to fit in the destination’s format" (§5.1)

Obviously, addition of real numbers is commutative, so the intermediate result produced for addition(a,b) must be equal to that produced for addition(b,a). I hope, but cannot guarantee, that the rounding applied to that intermediate result would not then depend on the order of operands provided to the addition operator.

3. "The operation addition(x, y) computes x+y. The preferred exponent is min(Q(x), Q(y))." (§5.4.1). This is the entire definition of addition, as far as I could find. (It's also defined, just above this statement, as being a general-computational operation. According to §5.1, a general-computational operation is one which produces floating-point or integer results, rounds all results according to §4, and might signal floating-point exceptions according to §7.)

4. The standard encourages programming language implementations to treat IEEE 754 addition as commutative (§10.4):

> A language implementation preserves the literal meaning of the source code by, for example:

> - Applying the properties of real numbers to floating-point expressions only when they preserve numerical results and flags raised:

> -- Applying the commutative law only to operations, such as addition and multiplication, for which neither the numerical values of the results, nor the representations of the results, depend on the order of the operands.

> -- Applying the associative or distributive laws only when they preserve numerical results and flags raised.

> -- Applying the identity laws (0 + x and 1 × x) only when they preserve numerical results and flags raised.

This looks like a guarantee that, in IEEE 754 addition, "the representation of the result" (i.e. the sign/exponent/significand triple, or a special infinite or NaN value - §3.2) does not "depend on the order of the operands". §3.2 specifically allows an implementation to map multiple bitstrings ("encodings") to a single "representation", so it's possible that the bit pattern of the result of an addition may differ depending on the order of the addends.

5. "Except for the quantize operation, the value of a floating-point result (and hence its cohort) is determined by the operation and the operands’ values; it is never dependent on the representation or encoding of an operand."

"The selection of a particular representation for a floating-point result is dependent on the operands’ representations, as described below, but is not affected by their encoding." (both from §5.2)

HOWEVER...

6. §6, dealing with infinite and NaN values, implicitly contemplates that there might be a distinction between addition(a,b) and addition(b,a):

> Operations on infinite operands are usually exact and therefore signal no exceptions, including, among others,

> - addition(∞, x), addition(x, ∞), subtraction(∞, x), or subtraction(x, ∞), for finite x (§6.1)

Re: 0.30000000000000004

#152
post #111

That's one of the worst domain name ever. When the topic comes along, I always remember about "that single-serving website with a domain name that looks like a number" and then take a surprisingly long time searching for it. I have written a test framework and I am quite familiar with these problems, and comparing floating point numbers is a PITA. I had users complaining that 0.3 is not 0.3. The code managing these c…

It's the first result for "floating point site" on Google. Sure the domain itself is impossible to remember, but you don't have to remember the actual number, just what it stands for.

Remember filter bubble. My first result is not your first result. (although in this case it happens to be, but we both probably search a lot on programming)

Re: 0.30000000000000004

#153
post #71

A thread from 2017.00000000000: https://news.ycombinator.com/item?id=14018450 2015.000000000000: https://news.ycombinator.com/item?id=10558871

FWIW, both of those can be expressed exactly by floating-point numbers ;)

Right all integers up to 2^53 (or something like that) can be (in double precision).

I assume that's the reason they made the mantissa linear, even though having the whole thing logarithmic makes more sense.

Re: 0.30000000000000004

#155
post #148

Earlier quoted context omitted.

US currency can go to more than two decimal places... http://blogs.reuters.com/ben-walsh/2013/11/18/do-stocks-real... I guess it's time for someone to write an "Assumptions Programmers make about money" post.

Falsehoods programmers believe about prices: https://gist.github.com/rgs/6509585

Interesting list, though I'm not sure what do they mean by n. 7

Re: 0.30000000000000004

#156
post #17

I remember in college when we learned about this and I had the thought, "Why don't we just store the numerator and denominator?", and threw together a little C++ class complete with (then novel, to me) operator-overloads, which implemented the concept. I felt very proud of myself. Then years later I learned that it's a thing people actually use: https://en.wikipedia.org/wiki/Rational_data_type

Clojure has Ratio numbers. https://clojuredocs.org/clojure.core/rationalize

Re: 0.30000000000000004

#157
post #111

That's one of the worst domain name ever. When the topic comes along, I always remember about "that single-serving website with a domain name that looks like a number" and then take a surprisingly long time searching for it. I have written a test framework and I am quite familiar with these problems, and comparing floating point numbers is a PITA. I had users complaining that 0.3 is not 0.3. The code managing these c…

> That's one of the worst domain name ever.

Maybe the creator's theory is that people will search for 0.30000000000000004 when they run into it after running their code.

Re: 0.30000000000000004

#158
post #79

Earlier quoted context omitted.

I haven't worked in fintech but I've read that money is often represented (at least in storage) as plain integers, since for example US currency only ever goes to two decimal places. But I guess once you start operating on it you run into potential truncation unless you use rationals.

You can still get reasonable enough approximations with more than two decimals if you do something like `int64 myWorkingMoneyVal = currentMoney * 100000`, do your work, then divide the final result by 100000. You still risk some potential truncation if your work involves division, but the larger your multiplier that you're working with, the larger divisor at the end, which will help minimize how much of an error this…

Google uses 1000000 as multiplier in their APIs.

Edit: And they forbid equality comparisons for rationals. For some reason even >= is not allowed.

Re: 0.30000000000000004

#159
post #79
post #67

Earlier quoted context omitted.

It's actually in use in many places, for things like handling currency and money, and for when you get funny corner cases involving rounding such numbers and pooling the change. Whenever I see someone handling currency in floats, something inside me wither and die a small death.

I haven't worked in fintech but I've read that money is often represented (at least in storage) as plain integers, since for example US currency only ever goes to two decimal places. But I guess once you start operating on it you run into potential truncation unless you use rationals.

I have developed a payment plan calculator for asset based finance and you would be amazed how many different rounding schemes and day counters (for fractional periods) exist and are actively used.

Re: 0.30000000000000004

#160
post #143

Earlier quoted context omitted.

IEEE floats are pretty complicated, but today’s CPUs have dedicated support for those and not for rationals, so we use them where we probably shouldn’t.

IEEE floats are absolutely great for many applications where rationals would be overkill or even inappropriate. A videogame doesn't care if the result is 0.3 or 0.30000000000000004. Even some scientific applications can use floats if the coder knows what they're doing. The problem is devs who don't understand what they're doing and just think that they can use floats in every situation and it'll just work out fine. T…

I love this demonstration of that phenomenon: https://twitter.com/schteppe/status/1143111757751357440?s=20
Post reply on HN