6 ms·
There is a huge misconception here which really should be clarified in the title. Erlang has an "exactly equal" or strict equality operator, called =:=, which i
by ComplexSystems 3y ago
There is a huge misconception here which really should be clarified in the title. Erlang has an "exactly equal" or strict equality operator, called =:=, which is different from just usual equality, which is ==. The usual equality operator will keep having +0.0 = -0.0, and floating point arithmetic will keep behaving as you would expect... It's that we no longer have +0.0 =:= -0.0, which is a very different thing (and frankly, makes sense - there should be some special operator that can differentiate between these two values).
- freddie_mercury 3y agoReading the article is what clarifies things. HN is full of people who think the world needs their hot take based on a headline, unfortunately.
- butterisgood 3y agoI read the first word of your reply and would like to counter you with “no! writing!”
- dang 3y ago"Please don't sneer, including at the rest of the community." It's reliably a marker of bad comments and worse threads. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html
- Trufa 3y agoWhat’s the use case for different values?
- lliamander 3y agoIt's a natural consequence of the IEEE 754 standard for floating point numbers.
- Tuna-Fish 3y agoTo be clear, it was added to the standard because there was user demand for it. Zero is already special cased in IEEE 754 (along with the rest of the denormals, because of the implied leading mantissa bit), the implementation would be no harder if you just only had a single zero. However, back when the standard was being created, when a single zero value was proposed there was pushback from people in the user community who depended on knowing which side of the zero they underflowed on their own floating point implementations. Many people think that negative zero is just an engineering artefact. This is not true, it is a feature that was asked for, debated, and then added... ... almost certainly because it was an engineering artefact in a previous system that someone managed to depend on, https://xkcd.com/1172/ https://xkcd.com/1172/ style.
- munk-a 3y ago> Many people think that negative zero is just an engineering artefact. This is not true, it is a feature that was asked for, debated, and then added... Allowing zero to be represented with two bit patterns was a feature that was advocated for to make bit operations easier - it was not decided that both zeroes should be distinguishable. This absolutely is an engineering artifact but you're quite correct that it was quite intentional.
- kragen 3y agoi think the rationale in https://people.freebsd.org/~das/kahan86branch.pdf https://people.freebsd.org/~das/kahan86branch.pdf goes well above and beyond 'an engineering artefact in a previous system that someone managed to depend on'
- kragen 3y agounfortunately this scan is missing some pages
- pmarreck 3y agoBecause two binary values that are not bit-for-bit equal should have an equality operator that can reflect that without resorting to conversion
- pclmulqdq 3y ago1/Infinity in 754 is 0. 1/(-Infinity) is -0. These numbers are not strictly equal in real number terms.
- munk-a 3y agoThese numbers are inequal in terms of storage - in real number terms zero has no sign and thus -0 and +0 are the same number. The source of their distinction is also important as it's just a pure point of convenience at the bit level - there are two separate bit patterns for 0 but both numbers are the same number.
- pclmulqdq 3y ago+/-0 often indicates an underflow on one side of 0 or the other. Certainly in real terms 1/(infinity) != -1/(infinity).
- adastra22 3y agoYou are overloading the word “real”. In terms of the mathematics of the reals, there is no difference. In terms of real-life pragmatics, 0 and -0 could be used to differentiate between different outcomes in a way that is sometimes useful.
- pclmulqdq 3y agoInfinity and -0 are not in the real numbers, so the expression there makes no sense if you are thinking strictly in the real numbers. If you assign real number bounds to what the floating point numbers mean, the expressions make sense. In floating point terms infinity tends to indicate overflow (any number that is too big to represent) and the 0's indicate underflows. So in more verbose terms, 1/(positive overflow) = (positive underflow) While -1/(positive overflow) = (negative underflow) In this case, since the positive overflow isn't really infinity and the underflows aren't really 0, they are not equal. In practice, -0 and the 0 can both also arise from situations that produce 0 exactly, too, but this is not that case. You may be thinking about how lim{x->inf}(1/x) = 0 = lim{x->inf}(-1/x), which is true. Infinity in floating point does not necessarily represent that limit, though, just any number that is too big. You may also notice that the limit is not in the range of the functions inside the limit. For all real x, 1/x != 0
- super256 3y agoFloat stuff like 1.f / (+0.f) = infinity and 1.f / (-0.f) = -infinity. And maybe complex number shenanigans and multi valued functions? Maybe someone familiar with mathematics can tell us more. :)
- wbl 3y agoThe best example on kahan's webpage is Borda's mouthpiece. Signed zero makes it look right, unsigned creates a singularity
- pclmulqdq 3y agoThere are actually very clear and technical numerical analysis reasons for all of the weird stuff that happens in IEEE 754. The zero behavior, in particular, is because of this sort of thing.
- layer8 3y agoPreserving the sign in case of arithmetic overflow/underflow.
- KETHERCORTEX 3y agoFloating point numbers don't represent all possible values, just a subset of values representable by a number of bits used. Therefore, in some cases it's reasonable to treat floating point numbers not as "exact point on a number scale", but rather a range between a number and the next possible representable number. In the case of +0.0 and -0.0, they can be treated as values between zero and the smallest representable number (about 5.4E-079 for 32 bit floats). It isn't a very common use case since dealing with such small numbers isn't a very common thing, but it is definitely a possibility.
- munk-a 3y agoHonestly - I rather dislike this change. I'd much rather have 0 & -0 be precisely equal to each other and have some obscure library function like `isNegativeZero` for the extremely rare cases they'd need to be differentiated. 0 and -0 being distinct values is honestly just an accident of convenience with how floats are stored - there are two bit patterns that result in a value of 0 but because they're different patterns we've assigned an unwarranted amount of distinction to them.
- sebzim4500 3y agoI don't think it's just that. 1/0 is infinity but 1/(-0) is -infinity
- rpaddock 3y agoRigorously division by zero is "undefined" in mathematics.
- pvillano 3y agoYou can totally define division by zero. "There are mathematical structures in which [dividing by zero] is defined. [...] However, such structures do not satisfy every ordinary rule of arithmetic (the field axioms)." https://wikipedia.org/wiki/Division_by_zero https://wikipedia.org/wiki/Division_by_zero You're familiar with the ordinary rules of arithmetic (ORA!) applied to the real numbers. However, there are many number systems that follow different rules. The rules of arithmetic for floats, wraparound ints, elliptic curves, and asymptotic analysis are all different from ORA! (and each other) but they are useful in their own ways.
- distortedsignal 3y agoShouldn't both of those be NaN? Does Erlang have a NaN?
- xxs 3y ago>both of those be NaN Totally NOT. NaN is defined as 0.0/0.0. That's it.
- 2h 3y agothere is no such thing as -0. if you want to say "zero approaching from negative one", fine, say that. but that IS NOT the same thing as -0. zero is just zero, it doesn't have a sign. some people just want everything to fit in a nice neat box, and sometimes folks, life is not like that. this is an awful change, injecting meaning where there is no room for it.
- deleted 3y ago[deleted]
- derefr 3y ago-0 exists. It's just not a mathematical object. It's an IEEE754 signed-magnitude bit-pattern — one that is distinct from the IEEE754 signed-magnitude bit-pattern we call +0. Both of these bit-patterns encode the semantic meaning of the mathematical object 0; but that doesn't mean that the bit patterns are the same "thing." Compare/contrast: the JSON document "0" vs the JSON document "0.0". Both encode the same type (JSON only has one Number type) and so the same mathematical object — which is, again, 0 — but these are distinct JSON documents. And that's the whole point of this change. Erlang == is mathematical equality. Erlang =:= is (encoded bit-pattern) representational equality. Which is often the kind of equality you care about, if you have canonicalization happening at parse time, and so you want to implicitly assert (usually for added efficiency!) that the values you got after parsing + mathing are not only mathematically equal to some value, but representationally equal to that value. --- (If this irks you as a mathematician, you could model IEEE754 as its own mathematical group — a lattice, I think? — of which +0 and -0 would be members. Along with with some — but not all — base-2 rationals; and a random assortment of signalling and non-signalling NaNs.)
- bee_rider 3y agoSo, in Erlang it will be the case that: +0.0 == -0.0 is true, I guess because they are very close +0.0 =:= -0.0 is false, I guess because they have different bits A =:= B for two different numbers of course, because they have different bits How does == work for other very close floating point values in Erlang? Is there some inconsistency here?
- throwawaymaths 3y agoThe only other distinction between == and =:= is for integers and floats. Integers are not =:= to the corresponding float, but are ==, so it has nothing to do with closeness. -0.0 is a weird dumb non mathematical value that IEEE 754 put in (for example the standardized value for sqrt(-0.0) is not even justifiable based on their choices). I think they didn't want 1/(1/-Inf) to be Inf, or something. In the end think of erlang's "==" as "equal in value" and "=:=" as "equal in representation in memory". Now if you really want to raise the hackles of someone using Erlang, should ask why integers and floats don't have a well ordering, and what you should do when you sort them.
- shultays 3y agoIt is not about being very close. IEEE says "Comparisons shall ignore the sign of zero" and erlang (or rather CPU instructions erlang outputs for float == float) respects that While =:= is not something mandated by IEEE. Erlang implements such an operator on floats and it decides to compare false for 0.0 & -0.0. So it probably compares bits/does integer comparisons on same data
- bee_rider 3y agoAh, so == is compliant, and =:= is extra. Makes sense!
- longemen3000 3y agoi don't use Erlang (mainly Julia), but this change makes a lot of sense. in Julia, there is the == operator (value equality) and the === operator (value egality). 0.0 == -0.0,because they have the same "value". but they aren't identical (the bits are different), so !(0.0 === -0.0).
- tialaramex 3y ago> there should be some special operator that can differentiate between these two values). What for though? I was expecting as I learned Rust that I would soon find the == operator (which is just the predicate PartialEq::eq) wasn't quite enough and need some === type operator (Rust doesn't have one), but I never did. Turns out actually in most cases equality is what I cared about.
- rch 3y agoThere is an example in the article about compiler optimization, and they state that other similar instances may exist.
- tialaramex 3y agoThe example for the compiler just seems like it wants a property that types don't necessarily even have (Equivalence), so my instinct would be that it's probably just broken and this is the tip of the iceberg or if the compiler does care about this property it should know floats don't have Equivalence and thus 0.0 == -0.0 isn't cause to perform this optimisation.
- kragen 3y agoit's using the =:= operator you say it should be using, not the == operator you incorrectly say it is using however, that operator was originally defined incorrectly, and now they are fixing that bug
- tialaramex 3y agoSo far the only example I've been given of this operator is that it's what the compiler uses to decide equivalence, which is a situation where the correct answer was categorically no. The belief seems to be that this code is fine if we mistakenly unify cases where we think the IEEE floating point number had the same representation, and I don't buy that this is better than unifying -0.0 and 0.0 in the example, I think it'll be the exact same outcome.
- hajile 3y agoWhat about the N number of NaN values that are treated the same, but are physically different values?