4 ms·
This is how you get the equivalent float value from an integer, assuming it fits within that 53 bit range. You're correct that you could pick a larger exponent
by ohazi 5y ago
This is how you get the equivalent float value from an integer, assuming it fits within that 53 bit range. You're correct that you could pick a larger exponent at the expense of being able to store consecutive integers.
Edit: Ignore this, I'm wrong.
- dnautics 5y agono, it is not. There is a "hidden" "one" bit, the fraction part "XXX..." of the IEEE 754 float represents 1.XXXX... to be multiplied by the (offset) exponent. The exponent for the integer 2 in f64 is different from the exponent section for the integer 1, this is easy to verify: const std=@import("std"); test "IEEE fp representation" { std.debug.print("\n{x}\n", .{@bitCast(u64, @as(f64, 1.0))}); std.debug.print("\n{x}\n", .{@bitCast(u64, @as(f64, 2.0))}); } gives 3ff0000000000000 4000000000000000 note that the fraction parts for both 1.0 and 2.0 are entirely zero, as they are powers of two times [1].00000000... The "hidden bit", while tricky and hard to understand, is probably one of the few truly good decisions that IEEE-754 comittee made out of a lot of kludgey compromises. Note that if they had done it the way you suggest, there would be degenerate representations for the same number, leading to a much smaller total possible representations for the same bitspace (this is a minor problem for most object-based "Decimal" number systems used for financial Txs -- you often need to use a specialized equality function instead of the language builtin), the "hidden one" ensures that every binary form has a uniquely represented value, not counting craziness with NaNs, and plus/minus zero, sigh.
- ohazi 5y agoDoh. You're right. And that's even why they call it the fraction, because it's the fractional component of that 1.XXX number between [1.0, 2.0). My brain fart was forgetting how floats work, seeing that the integer-resolution range for both single and double precision floats was exactly the number of bits in the fraction + the sign bit and then pattern matching.
- dnautics 5y agoI think it would be interesting to explore a type where you nan-box integers, which is what I thought you might be talking about, and it would be fascinating if JS did that. Don't know if it's worth the space savings over a simple union type, tbh.
- mabster 5y agoThis. But you can get pretty close to "stuffing in the bits". What we used to do to get a random float: Set the exponent to 0 and stuff in bits for the significand. This gets you a random float in the range [1,2). Now subtract 1.0. Note that this misses many floating point values that should be selectable if you wanted all floats between 1 and 2, but it was good enough for video games. It's worth pointing out that IEEE 754-2008 has decimal numbers like you describe without the hidden bit. But for decimals this can be really useful because numbers "remember" their exponent. So if you're doing addition of dollar values, for example, .84 + .12 = 1.00 rather than 1 (i.e. it remembers its significant digits).
- dnautics 5y agoRemembering significant digits is not really that important in fintech applications, as you're usually in a fixed-point system that is pinned to the currency (dollar transactions usually down to the cent, handful of arabics down to the millimes, yen cut off at single unit).