Float Toy
evanw.github.io
evanw.github.io
This intuitively makes it obvious why, for example, 1/3 can't be represented. I find the rational form like a/b easier to understand than the "scientific notation" form like a×2^b.
Why not just write a * 2^b. Your a here, if supposed to represent the mantissa, is not an integer. This form doesn’t really clarify the relationship to the concept of a dyadic rational.
To write the floating point number as a dyadic rational treating a as an integer you would have something like (2^(53) + a) / 2^(53 - b).
But arbitrary dydadic rationals cannot be represented by a single floating point number. If you want arbitrary dyadic rationals you need the sum of a list of floats.
* * *
I think what you might be getting at is starting by teaching people about fixed-point binary numbers? Or just binary fractions in general, analogous to the usual decimal fractions?
That would be clearer to say than anything about “dyadic rationals”. After going through a typical primary school, people have the concept of “terminating decimals”, rather than a concept of “ten-adic rationals”.
If you're comfortable thinking about shifting integers, then perhaps this is a simple way to think about floats. For me, it's easier than thinking about them as fractions.
Scale is the number of dec digits after the decimal point and length is the number of significant figures.
See `man bc`
(As a follow-up, since I can't edit: This isn't exactly correct, because of the leading "1.", but it's close enough to aid understanding.)
One interesting thing you'll notice about IEEE754 is that the values sort naturally if you interpret them as sign-magnitude integers:
00000000 0
00000001 1.4e-45 (smallest representable positive value)
00000002 2.8e-45 (next-smallest representable positive value)
007fffff 1.1754942e-38
00800000 1.17549435e-38
3f000000 0.5
3f800000 1.
3fffffff 1.9999999
40000000 2.
40400000 3.
60000000 3.6893488e19
7f000000 1.7014118e38
7f7fffff 3.4028235e38 (largest finite value)
7f800000 Infinity
7f800001 first NaN
7fffffff last NaN
In other words, if you count up in floats, it starts at 0 and goes up by increasingly larger amounts, then the number right "after" the "largest" is Infinity, followed by all the NaNs to the end of the range. The negative side is a "mirror image", the only difference being the highest (sign) bit is set.With a few bit-twiddling tricks you can even make them radix-sortable, as explained by Malte Skarupke:
> Michael Herf has also discovered a good way to generalize this to floating point numbers: Reinterpret cast the float to a uint32, then flip every bit if the float was negative, but flip only the sign bit if the float was positive. The same trick works for doubles and uint64s. Michael Herf explains why this works in the linked piece, but the short version of it is this: Positive floating point numbers already sort correctly if we just reinterpret cast them to a uint32. The exponent comes before the mantissa, so we would sort by the exponent first, then by the mantissa. Everything works out. Negative floating point numbers however would sort the wrong way. Flipping all the bits on them fixes that. The final remaining problem is that positive floating point numbers need to sort as bigger than negative numbers, and the easiest way to do that is to flip the sign bit since it’s the most significant bit.
Up until recently in most JS engines it was faster to sort typedarrays with a custom radix sort than with the built-in sort (seems to no longer be the case, thank goodness)
[0] https://probablydance.com/2016/12/27/i-wrote-a-faster-sortin...
Minor differences to the total ordering of the ints:
* IEEE NaNs always compare false
* IEEE +zero and -zero compare equal (that's the only case I'm aware of where you can have floats with x == y, but 1/x != 1/y, because +inf != -inf).
[1] Note that the ULP can get pretty large. If you have 1e23 as a float, you can add a million to it, and still get back the same number (because the next float is so far away).
https://en.wikipedia.org/wiki/Half-precision_floating-point_...
But most importantly I think best feature of the one in the submission is something it doesn't even mention in the description - it has a "click and drag to write bits" feature that I think is much easier to use/follow than the 2 dragging section on that one.
The individual bit flips also can be useful. It really depends what you want to use it for.
Then this morning on the train I started wondering: "wait, but how does floating point addition even make sense?!"... I'm still stumped on that one - I need "Float Addition Toy" ;)
(Pro-tip: it took me way too long to figure out that you can click and drag to set/clear the bits quickly)
Basically, you rewrite one of the numbers so that the exponents match, then sum the mantissas. There are a few extra steps, though: https://imgur.com/fgOH4sS
A "floating point addition toy" would be way cool!
f *= 0;
Is not the same operation as:
f = 0;
Since the former will retain the sign bit.
Is that a bug or do I not understand how IEEE754 works (very likely :p)?
Note that float toy doesn't actually show the mantissa value, only the final value. So if the value goes from 6.709679e-39 to 1.8464622e-38, then it was doubled.
EDIT: Oh! I see what you mean. I was wrong; obviously it does show the mantissa.
Yes, that seems like a bug. Shouldn't the mantissa always be in the range [0.0 .. 1.0)?
On the other hand, maybe it behaves differently when the exponent is negative. If you don't understand how IEEE754 works, then apparently I don't either, so thanks for pointing that out.
EDIT2: Ok, comparing with https://float.exposed/0x40490fdb makes me more certain that both sites are wrong.
On float.exposed, the exponent can’t ever go negative, which is clearly bogus. Exponent “128” should read “1”. It’s showing the raw binary unsigned value, which is misleading, since you want to know the int8 signed value.
But toggling the exponent bits should never affect the mantissa. That’s also bogus.
I think float toy is the superior visualization, and they should fix the bug. I wonder if there’s anywhere to report it....
https://stackoverflow.com/questions/8341395/what-is-a-subnor...
If the exponent is 0, then:
the leading bit becomes 0
the exponent is fixed to -126 (not -127 as if we didn't have this exception)
Such numbers are called subnormal numbers (or denormal numbers which is synonym).
All normal floating-point numbers have an implicit leading significant bit of 1. If the exponent field goes from 1 to 0, then this corresponds to changing the implicit leading bit to a 0, not to decreasing the exponent.I understand there’s an implicit “hidden” bit, but what conditions cause it to become 0 instead of 1? And does that bit represent the sign of the exponent, or something else?
After reading https://stackoverflow.com/questions/8341395/what-is-a-subnor... more carefully, I am more confused than ever. Both visualization sites seem to be leaving out key details. And subnormals only seem to apply when exponent = 0; the visualization problem that OP mentioned happens whenever the leading exponent bit is set to 0, but the rest of the bits can be anything.
It's not a matter of the "significant bit", but whether the WHOLE exponent is 0 or not. An exponent of 0 is a special case; as soon as you set ANY bit in that exponent, the mantissa goes back to the "implicit 1" prepended bit.
> Also, if the significant bit is always 1, how are negative exponents represented?
Exponents are represented in a "biased representation", counting up from 2-127.
> I understand there’s an implicit “hidden” bit, but what conditions cause it to become 0 instead of 1?
Exponent bits being all 0.
> And does that bit represent the sign of the exponent, or something else?
It represents the leading bit of the mantissa.
Thanks for the explanations.
This anecdote is from the frontlines of the Xbox 360. :)
In addition, many hardware implementations are much slower on denormals; some x87 implementations were 100s of cycles slower on denormals, NaN and Infinity.
A colleague of mine was around during the IEEE-754 days and said the hardware people pushed against denormals and the software people won (possibly with a professor stacking the committee with former students of his? I'm not clear on the details).
210,828,704
210,828,720
32 bit integers are precise enough. If you define 180 degrees West as INT_MIN and 180 degrees East as INT_MAX your precision is about a foot.
Although 32 bit floats are precise enough in some areas of Africa because it's closer to the 0,0 point. But it'll fall down if you're anywhere else in the world.
Add a (+) and (-) button to move up or down to the nearest floating point number.
Show the local precision (not sure if this is the correct term), i.e. the maximum difference between the current float and the two nearest ones.
Otherwise a pound of written explanation might still make sense.
Thanks for this!
So if the third red bit is 1, it's 1 x 2^-3, i.e 1 x 1/(2^3), i.e. 1 x 1/8, i.e. 0.125.
I'm not a floating-point fan (I do all computations in integer wherever possible/feasible), but I've been following the universal number story since it was announced because it seems less painful/gross than IEEE floating-point on many fronts, here's a github with a good about page about it: https://github.com/stillwater-sc/universal
Would be nice to get various 16-bit float formats as well. They're getting more and more common in graphics and NN domains.
Or perhaps generic n-width exponent and m-width mantissa.
https://github.com/kstenerud/compact-float/blob/master/compa...