Commit 4a35d7eeeb

Marc Tiehuis <marctiehuis@gmail.com>
2018-06-28 10:12:03
Correct hex-float parsing
Unblocks #495.
1 parent 2fa588e
Changed files (2)
src
test
cases
src/tokenizer.cpp
@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {
             // Mask the sign bit to 0 since always non-negative lex
             const uint64_t exp_mask = 0xffffull << exp_shift;
 
-            if (shift >= 64) {
+            // must be special-cased to avoid undefined behavior on shift == 64
+            if (shift == 128) {
+                f_bits.repr[0] = 0;
+                f_bits.repr[1] = sig_bits[0];
+            } else if (shift == 0) {
+                f_bits.repr[0] = sig_bits[0];
+                f_bits.repr[1] = sig_bits[1];
+            } else if (shift >= 64) {
                 f_bits.repr[0] = 0;
                 f_bits.repr[1] = sig_bits[0] << (shift - 64);
             } else {
                 f_bits.repr[0] = sig_bits[0] << shift;
-                f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)));
+                f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
             }
 
             f_bits.repr[1] &= ~exp_mask;
test/cases/math.zig
@@ -296,6 +296,14 @@ test "quad hex float literal parsing in range" {
     const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
 }
 
+test "quad hex float literal parsing accurate" {
+    const a: f128 = 0x1.1111222233334444555566667777p+0;
+
+    // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
+    const expected: u128 = 0x3fff1111222233334444555566667777;
+    assert(@bitCast(u128, a) == expected);
+}
+
 test "hex float literal within range" {
     const a = 0x1.0p16383;
     const b = 0x0.1p16387;