authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-06-28 20:12:03+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-06-28 20:12:03+12:00
log4a35d7eeebec3f345e2482bc189f07c19dcf6f8b
treec83abddc3c635fb9daa4ff9b85ebf19a341948d2
parent2fa588e81d60cfe319446bd0483c6bf296f40c40

Correct hex-float parsing

Unblocks #495.

2 files changed, 17 insertions(+), 2 deletions(-)

src/tokenizer.cpp+9-2
...@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {...@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {
357 // Mask the sign bit to 0 since always non-negative lex357 // Mask the sign bit to 0 since always non-negative lex
358 const uint64_t exp_mask = 0xffffull << exp_shift;358 const uint64_t exp_mask = 0xffffull << exp_shift;
359359
360 if (shift >= 64) {360 // must be special-cased to avoid undefined behavior on shift == 64
361 if (shift == 128) {
362 f_bits.repr[0] = 0;
363 f_bits.repr[1] = sig_bits[0];
364 } else if (shift == 0) {
365 f_bits.repr[0] = sig_bits[0];
366 f_bits.repr[1] = sig_bits[1];
367 } else if (shift >= 64) {
361 f_bits.repr[0] = 0;368 f_bits.repr[0] = 0;
362 f_bits.repr[1] = sig_bits[0] << (shift - 64);369 f_bits.repr[1] = sig_bits[0] << (shift - 64);
363 } else {370 } else {
364 f_bits.repr[0] = sig_bits[0] << shift;371 f_bits.repr[0] = sig_bits[0] << shift;
365 f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)));372 f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
366 }373 }
367374
368 f_bits.repr[1] &= ~exp_mask;375 f_bits.repr[1] &= ~exp_mask;
test/cases/math.zig+8
...@@ -296,6 +296,14 @@ test "quad hex float literal parsing in range" {...@@ -296,6 +296,14 @@ test "quad hex float literal parsing in range" {
296 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;296 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
297}297}
298298
299test "quad hex float literal parsing accurate" {
300 const a: f128 = 0x1.1111222233334444555566667777p+0;
301
302 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
303 const expected: u128 = 0x3fff1111222233334444555566667777;
304 assert(@bitCast(u128, a) == expected);
305}
306
299test "hex float literal within range" {307test "hex float literal within range" {
300 const a = 0x1.0p16383;308 const a = 0x1.0p16383;
301 const b = 0x0.1p16387;309 const b = 0x0.1p16387;