authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2017-09-28 19:15:06+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2017-09-28 23:33:36+13:00
log9dfe217be38289b0c9e662d1a0e7c0231bf42a7d
tree205d5ac64bf5f7a896fdd576a3e284b06b6cf714
parentfd5a5db400995d80015448d19e92daaca71a7f72

Allow 128-bit hex float literals

Closes #499.

5 files changed, 47 insertions(+), 27 deletions(-)

src/tokenizer.cpp+31-18
...@@ -303,7 +303,7 @@ static void end_float_token(Tokenize *t) {...@@ -303,7 +303,7 @@ static void end_float_token(Tokenize *t) {
303 return;303 return;
304 }304 }
305305
306 if (!bigint_fits_in_bits(&t->specified_exponent, 64, true)) {306 if (!bigint_fits_in_bits(&t->specified_exponent, 128, true)) {
307 t->cur_tok->data.float_lit.overflow = true;307 t->cur_tok->data.float_lit.overflow = true;
308 return;308 return;
309 }309 }
...@@ -314,39 +314,52 @@ static void end_float_token(Tokenize *t) {...@@ -314,39 +314,52 @@ static void end_float_token(Tokenize *t) {
314 }314 }
315 t->exponent_in_bin_or_dec = (int)(t->exponent_in_bin_or_dec + specified_exponent);315 t->exponent_in_bin_or_dec = (int)(t->exponent_in_bin_or_dec + specified_exponent);
316316
317 if (!bigint_fits_in_bits(&t->significand, 64, false)) {317 if (!bigint_fits_in_bits(&t->significand, 128, false)) {
318 t->cur_tok->data.float_lit.overflow = true;318 t->cur_tok->data.float_lit.overflow = true;
319 return;319 return;
320 }320 }
321321
322 uint64_t significand = bigint_as_unsigned(&t->significand);322 // A SoftFloat-3d float128 is represented internally as a standard
323 uint64_t significand_bits;323 // quad-precision float with 15bit exponent and 113bit fractional.
324 uint64_t exponent_bits;324 union { uint64_t repr[2]; float128_t actual; } f_bits;
325 if (significand == 0) {325
326 // 0 is all 0's326 if (bigint_cmp_zero(&t->significand) == CmpEQ) {
327 significand_bits = 0;327 f_bits.repr[0] = 0;
328 exponent_bits = 0;328 f_bits.repr[1] = 0;
329 } else {329 } else {
330 // normalize the significand330 // normalize the significand
331 if (t->radix == 10) {331 if (t->radix == 10) {
332 zig_panic("TODO: decimal floats");332 zig_panic("TODO: decimal floats");
333 } else {333 } else {
334 int significand_magnitude_in_bin = clzll(1) - clzll(significand);334 int significand_magnitude_in_bin = 127 - bigint_clz(&t->significand, 128);
335 t->exponent_in_bin_or_dec += significand_magnitude_in_bin;335 t->exponent_in_bin_or_dec += significand_magnitude_in_bin;
336 if (!(-1022 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec <= 1023)) {336 if (!(-16382 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec <= 16383)) {
337 t->cur_tok->data.float_lit.overflow = true;337 t->cur_tok->data.float_lit.overflow = true;
338 return;338 return;
339 }
340
341 uint64_t sig_bits[2] = {0, 0};
342 bigint_write_twos_complement(&t->significand, (uint8_t*) sig_bits, 128, false);
343
344 const uint64_t shift = 112 - significand_magnitude_in_bin;
345 const uint64_t exp_shift = 48;
346 // Mask the sign bit to 0 since always non-negative lex
347 const uint64_t exp_mask = 0xfffful << exp_shift;
348
349 if (shift >= 64) {
350 f_bits.repr[0] = 0;
351 f_bits.repr[1] = sig_bits[0] << (shift - 64);
339 } else {352 } else {
340 // this should chop off exactly one 1 bit from the top.353 f_bits.repr[0] = sig_bits[0] << shift;
341 significand_bits = ((uint64_t)significand << (52 - significand_magnitude_in_bin)) & 0xfffffffffffffULL;354 f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)));
342 exponent_bits = t->exponent_in_bin_or_dec + 1023;
343 }355 }
356
357 f_bits.repr[1] &= ~exp_mask;
358 f_bits.repr[1] |= (uint64_t)(t->exponent_in_bin_or_dec + 16383) << exp_shift;
344 }359 }
345 }360 }
346 uint64_t double_bits = (exponent_bits << 52) | significand_bits;361
347 double dbl_value;362 bigfloat_init_128(&t->cur_tok->data.float_lit.bigfloat, f_bits.actual);
348 safe_memcpy(&dbl_value, (double *)&double_bits, 1);
349 bigfloat_init_64(&t->cur_tok->data.float_lit.bigfloat, dbl_value);
350}363}
351364
352static void end_token(Tokenize *t) {365static void end_token(Tokenize *t) {
std/math/expm1.zig+1-1
...@@ -255,7 +255,7 @@ fn expm1_64(x_: f64) -> f64 {...@@ -255,7 +255,7 @@ fn expm1_64(x_: f64) -> f64 {
255 if (k < 0 or k > 56) {255 if (k < 0 or k > 56) {
256 var y = x - e + 1.0;256 var y = x - e + 1.0;
257 if (k == 1024) {257 if (k == 1024) {
258 y = y * 2.0 * 0x1.0p1022 * 10;258 y = y * 2.0 * 0x1.0p1023;
259 } else {259 } else {
260 y = y * twopk;260 y = y * twopk;
261 }261 }
std/math/scalbn.zig+2-2
...@@ -45,10 +45,10 @@ fn scalbn64(x: f64, n_: i32) -> f64 {...@@ -45,10 +45,10 @@ fn scalbn64(x: f64, n_: i32) -> f64 {
45 var n = n_;45 var n = n_;
4646
47 if (n > 1023) {47 if (n > 1023) {
48 y *= 0x1.0p1022 * 2.0;48 y *= 0x1.0p1023;
49 n -= 1023;49 n -= 1023;
50 if (n > 1023) {50 if (n > 1023) {
51 y *= 0x1.0p1022 * 2.0;51 y *= 0x1.0p1023;
52 n -= 1023;52 n -= 1023;
53 if (n > 1023) {53 if (n > 1023) {
54 n = 1023;54 n = 1023;
test/cases/math.zig+11-4
...@@ -241,14 +241,21 @@ test "allow signed integer division/remainder when values are comptime known and...@@ -241,14 +241,21 @@ test "allow signed integer division/remainder when values are comptime known and
241 assert(-6 % 3 == 0);241 assert(-6 % 3 == 0);
242}242}
243243
244test "float literal parsing" {244test "hex float literal parsing" {
245 comptime assert(0x1.0 == 1.0);245 comptime assert(0x1.0 == 1.0);
246}246}
247247
248test "quad hex float literal parsing in range" {
249 const a = 0x1.af23456789bbaaab347645365cdep+5;
250 const b = 0x1.dedafcff354b6ae9758763545432p-9;
251 const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534;
252 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
253}
254
248test "hex float literal within range" {255test "hex float literal within range" {
249 const a = 0x1.0p1023;256 const a = 0x1.0p16383;
250 const b = 0x0.1p1027;257 const b = 0x0.1p16387;
251 const c = 0x1.0p-1022;258 const c = 0x1.0p-16382;
252}259}
253260
254test "truncating shift left" {261test "truncating shift left" {
test/compile_errors.zig+2-2
...@@ -1901,14 +1901,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1901,14 +1901,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
19011901
1902 cases.add("float literal too large error",1902 cases.add("float literal too large error",
1903 \\comptime {1903 \\comptime {
1904 \\ const a = 0x1.0p1024;1904 \\ const a = 0x1.0p16384;
1905 \\}1905 \\}
1906 ,1906 ,
1907 ".tmp_source.zig:2:15: error: float literal out of range of any type");1907 ".tmp_source.zig:2:15: error: float literal out of range of any type");
19081908
1909 cases.add("float literal too small error (denormal)",1909 cases.add("float literal too small error (denormal)",
1910 \\comptime {1910 \\comptime {
1911 \\ const a = 0x1.0p-1023;1911 \\ const a = 0x1.0p-16384;
1912 \\}1912 \\}
1913 ,1913 ,
1914 ".tmp_source.zig:2:15: error: float literal out of range of any type");1914 ".tmp_source.zig:2:15: error: float literal out of range of any type");