authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-21 16:17:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-21 16:17:29-04:00
logaf509c68b01c8645e5efaeec7ea11e809f34ba7d
treedad7a1a927522c19f547a910d68647e0ce989a57
parentb5cc92f16391b1ff5d75e5e6b072b8338b3e8218
signaturelock-open Commit is signed but in an unrecognized format.

fix parsing of large hex float literals

closes #2083

2 files changed, 82 insertions(+), 10 deletions(-)

src/tokenizer.cpp+18-10
......@@ -326,7 +326,7 @@ static void end_float_token(Tokenize *t) {
326326 return;
327327 }
328328
329 // A SoftFloat-3d float128 is represented internally as a standard
329 // A SoftFloat-3e float128 is represented internally as a standard
330330 // quad-precision float with 15bit exponent and 113bit fractional.
331331 union { uint64_t repr[2]; float128_t actual; } f_bits;
332332
......@@ -345,29 +345,37 @@ static void end_float_token(Tokenize *t) {
345345 return;
346346 }
347347
348 uint64_t sig_bits[2] = {0, 0};
349 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
350
351 const uint64_t shift = 112 - significand_magnitude_in_bin;
352 const uint64_t exp_shift = 48;
353 // Mask the sign bit to 0 since always non-negative lex
354 const uint64_t exp_mask = 0xffffull << exp_shift;
348 const int shift = 112 - significand_magnitude_in_bin;
355349
356350 // must be special-cased to avoid undefined behavior on shift == 64
357351 if (shift == 128) {
352 uint64_t sig_bits[2] = {0, 0};
353 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
358354 f_bits.repr[0] = 0;
359355 f_bits.repr[1] = sig_bits[0];
360356 } else if (shift == 0) {
361 f_bits.repr[0] = sig_bits[0];
362 f_bits.repr[1] = sig_bits[1];
357 bigint_write_twos_complement(&t->significand, (uint8_t*) f_bits.repr, 128, false);
363358 } else if (shift >= 64) {
359 uint64_t sig_bits[2] = {0, 0};
360 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
364361 f_bits.repr[0] = 0;
365362 f_bits.repr[1] = sig_bits[0] << (shift - 64);
363 } else if (shift < 0) {
364 BigInt shift_bigint;
365 bigint_init_unsigned(&shift_bigint, -shift);
366 BigInt shifted_significand;
367 bigint_shr(&shifted_significand, &t->significand, &shift_bigint);
368 bigint_write_twos_complement(&shifted_significand, (uint8_t*) f_bits.repr, 128, false);
366369 } else {
370 uint64_t sig_bits[2] = {0, 0};
371 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
367372 f_bits.repr[0] = sig_bits[0] << shift;
368373 f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
369374 }
370375
376 const uint64_t exp_shift = 48;
377 // Mask the sign bit to 0 since always non-negative lex
378 const uint64_t exp_mask = 0xffffull << exp_shift;
371379 f_bits.repr[1] &= ~exp_mask;
372380 f_bits.repr[1] |= (uint64_t)(t->exponent_in_bin_or_dec + 16383) << exp_shift;
373381 }
test/stage1/behavior/math.zig+64
......@@ -307,6 +307,70 @@ test "quad hex float literal parsing accurate" {
307307 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
308308 const expected: u128 = 0x3fff1111222233334444555566667777;
309309 expect(@bitCast(u128, a) == expected);
310
311 const S = struct {
312 fn doTheTest() void {
313 var f1: f128 = 0x1.2eab345678439abcdefea56782346p+5;
314 expect(@bitCast(u128, f1) == 0x40042eab345678439abcdefea5678234);
315 const exp2ft = []f64{
316 0x1.6a09e667f3bcdp-1,
317 0x1.7a11473eb0187p-1,
318 0x1.8ace5422aa0dbp-1,
319 0x1.9c49182a3f090p-1,
320 0x1.ae89f995ad3adp-1,
321 0x1.c199bdd85529cp-1,
322 0x1.d5818dcfba487p-1,
323 0x1.ea4afa2a490dap-1,
324 0x1.0000000000000p+0,
325 0x1.0b5586cf9890fp+0,
326 0x1.172b83c7d517bp+0,
327 0x1.2387a6e756238p+0,
328 0x1.306fe0a31b715p+0,
329 0x1.3dea64c123422p+0,
330 0x1.4bfdad5362a27p+0,
331 0x1.5ab07dd485429p+0,
332 0x1.8p23,
333 0x1.62e430p-1,
334 0x1.ebfbe0p-3,
335 0x1.c6b348p-5,
336 0x1.3b2c9cp-7,
337 0x1.0p127,
338 -0x1.0p-149,
339 };
340
341 const answers = []u64{
342 0x3fe6a09e667f3bcd,
343 0x3fe7a11473eb0187,
344 0x3fe8ace5422aa0db,
345 0x3fe9c49182a3f090,
346 0x3feae89f995ad3ad,
347 0x3fec199bdd85529c,
348 0x3fed5818dcfba487,
349 0x3feea4afa2a490da,
350 0x3ff0000000000000,
351 0x3ff0b5586cf9890f,
352 0x3ff172b83c7d517b,
353 0x3ff2387a6e756238,
354 0x3ff306fe0a31b715,
355 0x3ff3dea64c123422,
356 0x3ff4bfdad5362a27,
357 0x3ff5ab07dd485429,
358 0x4168000000000000,
359 0x3fe62e4300000000,
360 0x3fcebfbe00000000,
361 0x3fac6b3480000000,
362 0x3f83b2c9c0000000,
363 0x47e0000000000000,
364 0xb6a0000000000000,
365 };
366
367 for (exp2ft) |x, i| {
368 expect(@bitCast(u64, x) == answers[i]);
369 }
370 }
371 };
372 S.doTheTest();
373 comptime S.doTheTest();
310374}
311375
312376test "hex float literal within range" {