Commit 90a32629c0

MovingtoMars <liam@bumblebee.net.nz>
2016-01-29 08:55:38
float printing mostly works
1 parent 650fdde
Changed files (1)
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
 }