From 90a32629c0120acba881c87e84b7291732703fbe Mon Sep 17 00:00:00 2001 From: MovingtoMars Date: Fri, 29 Jan 2016 20:55:38 +1300 Subject: [PATCH 1/4] float printing mostly works --- std/std.zig | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/std/std.zig b/std/std.zig index e991868e17..efb3bcdc01 100644 --- a/std/std.zig +++ b/std/std.zig @@ -108,6 +108,20 @@ pub struct OutStream { return amt_printed; } + pub fn print_f64(os: &OutStream, x: f64) -> %isize { + if (os.index + max_f64_digits >= os.buffer.len) { + %return os.flush(); + } + const amt_printed = buf_print_f64(os.buffer[os.index...], x, 4); + os.index += amt_printed; + + if (!os.buffered) { + %return os.flush(); + } + + return amt_printed; + } + pub fn flush(os: &OutStream) -> %void { const amt_written = write(os.fd, os.buffer.ptr, os.index); os.index = 0; @@ -229,6 +243,124 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize { return len; } +pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { + var decs = decimals; + if (decs >= max_u64_base10_digits) { + decs = max_u64_base10_digits - 1; + } + + if (x == f64_get_pos_inf()) { + const buf2 = "+Inf"; + @memcpy(&out_buf[0], &buf2[0], buf2.len); + return 4; + } else if (x == f64_get_neg_inf()) { + const buf2 = "-Inf"; + @memcpy(&out_buf[0], &buf2[0], buf2.len); + return 4; + } else if (f64_is_nan(x)) { + const buf2 = "NaN"; + @memcpy(&out_buf[0], &buf2[0], buf2.len); + return 3; + } + + var buf: [max_f64_digits]u8 = undefined; + + var len: isize = 0; + + // 1 sign bit + // 11 exponent bits + // 52 significand bits (+ 1 implicit always non-zero bit) + + const bits = f64_to_bits(x); + if (bits & (1 << 63) != 0) { + buf[0] = '-'; + len += 1; + } + + const rexponent: i64 = i64((bits >> 52) & ((1 << 11) - 1)); + const exponent = rexponent - 1023 - 52; + + if (rexponent == 0) { + buf[len] = '0'; + len += 1; + @memcpy(&out_buf[0], &buf[0], len); + return len; + } + + const sig = (bits & ((1 << 52) - 1)) | (1 << 52); + + if (exponent >= 0) { + // number is an integer + + if (exponent >= 11) { + // use XeX form + + // TODO support printing large floats + //len += buf_print_u64(buf[len...], sig << 10); + const str = "LARGEF64"; + @memcpy(&buf[len], &str[0], str.len); + len += str.len; + } else { + // use typical form + + len += buf_print_u64(buf[len...], sig << u64(exponent)); + buf[len] = '.'; + len += 1; + + var i: isize = 0; + while (i < decs) { + buf[len] = '0'; + len += 1; + i += 1; + } + } + } else { + // number is not an integer + + // print out whole part + len += buf_print_u64(buf[len...], sig >> u64(-exponent)); + buf[len] = '.'; + len += 1; + + // print out fractional part + // dec_num holds: fractional part * 10 ^ decs + var dec_num: u64 = 0; + + var a: isize = 1; + var i: isize = 0; + while (i < decs) { + a *= 10; + i += 1; + } + + // create a mask: 1's for the fractional part, 0's for whole part + var masked_sig = sig & ((1 << u64(-exponent)) - 1); + i = -1; + while (i >= exponent) { + var bit_set = ((1 << u64(i-exponent)) & masked_sig) != 0; + + if (bit_set) { + dec_num += usize(a) >> usize(-i); + } + + i -= 1; + } + + len += decs; + + i = len - 1; + while (i >= len - decs) { + buf[i] = '0' + u8(dec_num % 10); + dec_num /= 10; + i -= 1; + } + } + + @memcpy(&out_buf[0], &buf[0], len); + + len +} + fn min_isize(x: isize, y: isize) -> isize { if (x < y) x else y } From 850f6d2d0266c0b502f0f0aa39ae32de469d03d9 Mon Sep 17 00:00:00 2001 From: MovingtoMars Date: Fri, 29 Jan 2016 21:12:33 +1300 Subject: [PATCH 2/4] better f64_is_nan --- std/math.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/std/math.zig b/std/math.zig index 77a630d643..c563b45678 100644 --- a/std/math.zig +++ b/std/math.zig @@ -17,7 +17,11 @@ pub fn f64_get_neg_inf() -> f64 { } pub fn f64_is_nan(f: f64) -> bool { - 0x7FFFFFFFFFFFFFFF == f64_to_bits(f) // TODO improve to catch all cases + const bits = f64_to_bits(f); + const exp: i64 = i64((bits >> 52) & ((1 << 11) - 1)); + const sig = (bits & ((1 << 52) - 1)) | (1 << 52); + + sig != 0 && exp == (1 << 11) - 1 } pub fn f64_is_inf(f: f64) -> bool { From a6c2b013fd814245bf7da9711b7c3cdaf9b83dcc Mon Sep 17 00:00:00 2001 From: MovingtoMars Date: Fri, 29 Jan 2016 21:19:21 +1300 Subject: [PATCH 3/4] remove some magic numbers from float printing --- std/std.zig | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/std/std.zig b/std/std.zig index efb3bcdc01..dd83a4686b 100644 --- a/std/std.zig +++ b/std/std.zig @@ -244,6 +244,10 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize { } pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { + const numExpBits = 11; + const numRawSigBits = 52; // not including implicit 1 bit + const expBias = 1023; + var decs = decimals; if (decs >= max_u64_base10_digits) { decs = max_u64_base10_digits - 1; @@ -277,8 +281,8 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { len += 1; } - const rexponent: i64 = i64((bits >> 52) & ((1 << 11) - 1)); - const exponent = rexponent - 1023 - 52; + const rexponent: i64 = i64((bits >> numRawSigBits) & ((1 << numExpBits) - 1)); + const exponent = rexponent - expBias - numRawSigBits; if (rexponent == 0) { buf[len] = '0'; @@ -287,12 +291,12 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { return len; } - const sig = (bits & ((1 << 52) - 1)) | (1 << 52); + const sig = (bits & ((1 << numRawSigBits) - 1)) | (1 << numRawSigBits); if (exponent >= 0) { // number is an integer - if (exponent >= 11) { + if (exponent >= 64 - 53) { // use XeX form // TODO support printing large floats From 3fd6c0ce25f4bab3ae4e21519ac340e38a99cba3 Mon Sep 17 00:00:00 2001 From: MovingtoMars Date: Fri, 29 Jan 2016 21:22:15 +1300 Subject: [PATCH 4/4] fix some inaccuracy in float printing --- std/std.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/std/std.zig b/std/std.zig index dd83a4686b..efa8200c3e 100644 --- a/std/std.zig +++ b/std/std.zig @@ -332,7 +332,7 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { var a: isize = 1; var i: isize = 0; - while (i < decs) { + while (i < decs + 5) { a *= 10; i += 1; } @@ -350,6 +350,8 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { i -= 1; } + dec_num /= 100000; + len += decs; i = len - 1;