I have a suspicion that on a fundamental level, floating point isn't actually good for games or machine learning. They're just used because existing computers are so good at floating point number crunching, especially GPUs.
The most beautiful FP bug I remember was a denial of service in some webservers where by setting the header "Accepted Language: en-gb;q=0.3 en;q=0.8 ..." to a specific value you could send the official Java floating-point parser in an infinite loop (and this affected several Java webservers).
So at each webpage request, you were sending one CPU core of the webserver basically busy-looping. Hence crashing the webserver in a few requests at most.
Now it'd be heresy if I were to say that maybe, just maybe, had the standards mandated to use 0 to 100 for weighting instead of 0 to 1.0 we could have dodged a whole source of potential issues!?
No, no, I realize this is heresy: let's all keep using numbers that cannot even be represented correctly (except as strings), parse those strings into something approximately representing what's written in the string, then make more approximation errors while doing computation with these numbers, propagation errors, epsilon estimation errors, and keep insisting we all could have authored "What every computer scientist should known about floating-point numbers" (which is 80 pages long and, well, approaching a treaty) ; )
/rant off
I'm fascinated by how common it is for programmers to hate floats. Yes, if you write business software for a living you may not have much use for them. But there's a lot more to computing than business software.
From Microsoft BASIC to Javascript, many programmers have worked in languages that only have floats. Financial calculations involve exponential/log math much like scientific problems. There are issues with rounding and representation there (e.g. there is no such thing as $0.01 in floating point, only $0.50, $0.25, $0.125 and some sum of 1/2 fractions that comes very close to $0.01 and even reads in and writes out as $0.01 even though it isn't.)
Don't forget control systems.
That got fixed, but it seems a variation with signed NaN recently got fixed[1] in .Net Core (taking care to handle all the possible NaN values).
Floats are deceptively easy to use. Which is nice but kinda sucks too, given all the footguns they bring to the party.
// 0.0d / 0 equals 0x7ff8000000000000 (NaN)
// Math.sqrt(-1) equals 0xfff8000000000000 (NaN)
// 0x0p+0d is a funky way to specify 0x0000000000000000 (0)
// -0x0p+0d is a funky way to specify 0x8000000000000000 (-0)
// without 0xHEXp+NUMd my compiller optimizes "-0" literal to 0
// 0 == -0
0x0p+0d == -0x0p+0d
// hashCodes for 0 and -0 are different
Double.hashCode(0x0p+0d) != Double.hashCode(-0x0p+0d)
// hashCodes for different NaNs collapse to the same value
Double.hashCode(0.0d / 0) == Double.hashCode(Math.sqrt(-1))I never thought about that (I avoid FP as much as I can) but, oh boy, the can of worms!
.Net (or Java) OOP where an object's hashcode needs to give the same (or not?) value for 0.0 or -0.0: this is the kind of stuff nightmares are made off.
I'm sure this can be turned into some very funny "Java puzzler".
You can end up with zeros and infinities pretty easily because you overflow or underflow the range of floating point precision, and generally you want something sensible to happen in typical cases, even if some common arithmetic identities necessarily break down.
I would actually like a true signed zero (or rather "epsilon" value ), so -0 and +0 as distinct from "normal" 0 which is truly unsigned, neither positive nor negative. The former two would only arise from underflow, and the reason this is useful that if you underflow from below zero and invert that you want to get -∞ and if you underflow from above zero and invert that you want to get +∞. Inverting a signless zero should give NaN (instead it gives +∞, which is nonsense in basically any case where the domain is not inherently the non-negative reals already and the 0 did not come about by and underflow; in particular 1/0 should be NaN).
If anyone knows why this design was not chosen and what fundamental downsides it has, I'd love to hear it. Obviously representing three zeros is a tad more annoying, but IEEE754 has a lot of stuff that's annoying implementation wise but was added for nicer numerical behavior (e.g. denormals, and of course various "global" rounding modes etc. which probably qualify as a mistake in retrospect).
https://gis.stackexchange.com/questions/211796/if-degrees-is...
I made the above post due to a bug in the GPS on our routers. We had a customer close to the meridian in England.
http://www.thegreenwichmeridian.org/tgm/articles.php?article...
Western hemisphere is negative longitude, eastern hemisphere is positive. If your degrees are 0 (within ~100km? I can't remember exactly), then you still need to know if you're east or west of the meridian.
If you've got two numbers, +0.0000001 and -0.0000001, but you can't represent that precision, can you see how it's less bad to round to +0.0000 and -0.0000 rather than to just 0.0000? It's encoding strictly more information.
So whether or not there's a -0 or +0 in some "math" isn't relevant, because computers aren't using "some math" but very specific mathematical constructs that must be understood on their own terms. I haven't seen very many mathematical systems that have a reified "NaN" object that can be explicitly passed around as a valid value to functions. (I know of many systems that have a "bottom" but I would say bottom is usually presented not as an object you can "have" but as a property of some mathematical object. Haskell for instance uses this idea; there are some trivial ways to have or produce something that has the property of being "bottom", like calling "error", but you can't just "have the bottom value".)
Moreover, there are mathematical systems in which such things can appear. There are many exotic and interesting number systems in the mathematical world, which even a bachelor's degree in mathematics may only scratch the surface of, depending on which junior/senior level courses you take. Real numbers are without a doubt the most studied, and they do not contain a -0 (though even then you'll still see it show up sometimes as a special notation in limits), but they are the beginning of number systems, not the end.
I mention all this because it's important; it's a very common misconception that computers use the numbers like you learned in school, and it will lead to nothing but pain. The next misconception is that, ok, sure, they aren't those numbers exactly, but they're so close that I don't have to worry about it. This works as long as you don't push your floats too hard, and a lot of us don't, but also breaks down surprisingly quickly. It's important for programming professionals to understand in general that IEEE floats are their own thing. Whenever I use them I do at least take a couple of seconds to double-check mentally that the sharp pointy bits aren't going to stab me, even for simple things like adding durations of a request to some floating point accumulator for metric purposes.
So strictly speaking this number system doesn't have a representation of zero at all. Tiny measurements either round up or round down to +/- 1.
Take 2d laminar flow around a circle. The flow field splits right in the middle.
Signed zeros ensure that, along with graceful underflow, the local solution is not wonky.
Lots of complex-arithmetic examples too.
If you have a function that can experience underflow it can be useful to preserve the sign of the underflowing value.
Otherwise you'd need more checks to get that information.
Maybe when you're implementing floating point numbers in a way that's simple and widely applicable?
I'm only half joking, too, though I can't tell you what exactly having a distinct sign bit simplifies.
I can say off the bat that it is probably useful that a very small quantity that might otherwise lose enough precision to round to zero maintains its sign regardless.
As a sibling comment wrote, rounding numbers to -0 and +0 can provide extra information, though it may not be useful in all contexts.
php > $minus_zero = -0.0;
php > $plus_zero = +0.0;
php > var_dump(1.0 / $minus_zero);
PHP Warning: Uncaught DivisionByZeroError: Division by zero in php shell code:1The result of that division is a float with a value of -INF, INF being a constant that PHP treats as infinite.
But as of PHP 8 dividing by zero causes a fatal error and execution is halted.
This site is really good for comparing results in different PHP versions: https://3v4l.org/9Tl1I
I actually wasn't aware that PHP had an INF contant but seeing the warning in your output prompted me to dig a little bit deeper :)
minus_zero = -0.0
plus_zero = +0.0
parsed = float("-0.0")
print(1/minus_zero)
print(1/plus_zero)
print(1/parsed)
ZeroDivisionError Traceback (most recent call last)
<ipython-input-1-747f1b708c86> in <module>()
2 plus_zero = +0.0
3 parsed = float("-0.0")
----> 4 print(1/minus_zero)
5 print(1/plus_zero)
6 print(1/parsed)
ZeroDivisionError: float division by zero
edit: FormattingIt didn't die quickly though. The UNIVAC is still with us (in emulation) and that is likely the reason why the C standard addresses the question of negative zero integers. (Their handling is implementation specific, of course.)
>> 1 / -0.0
=> -Infinity
Although you have to put the 0.0, otherwise it treats it as an integer and makes it 0. iex(1)> -0.0 === 0.0
true
there's also explicitly no infinity or NaN, there is a software throw for all (core) implemented function domain failures.This has, however, recently come up for Nx (numerical elixir) which had to implement and standardize ways to shim these IEEE concepts back into the VM for interop purposes.
* Do they compare equal?
* If they're convertible to boolean, do they both evaluate to false?
* If you serialize/deserialize the value (e.g., to JSON and back), does it maintain the distinction?
* If you send this value to a database (esp. one with stored procedures), how does its behavior compare to your language?
Therefore; -0.0 + 2.0 = 2.0 and 0.0 + 2.0 = 2.0
But I see from the standard that dividing by zero returns infinity with the xor of the dividend and divisor. This also makes no sense - since zero has no sign, its not possible to tell what kind of infinity would result. It's strange that the standard permits both the infinity result from dividing by zero, and simultaneously supports signed zero.
<edit: add xor>