authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-29 11:20:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-29 11:20:34-07:00
log580df2f53055a25fcceb2717975270a6523f417e
tree70d82e4e2dfca6d4dafdd0be7a2fdb810ac32bb9
parent2e39d9881a68b7e4a4e765e06e898c2deeb30703
parent3fd6c0ce25f4bab3ae4e21519ac340e38a99cba3

Merge pull request #102 from MovingtoMars/float_print

float printing mostly works

2 files changed, 143 insertions(+), 1 deletions(-)

std/math.zig+5-1
...@@ -17,7 +17,11 @@ pub fn f64_get_neg_inf() -> f64 {...@@ -17,7 +17,11 @@ pub fn f64_get_neg_inf() -> f64 {
17}17}
1818
19pub fn f64_is_nan(f: f64) -> bool {19pub fn f64_is_nan(f: f64) -> bool {
20 0x7FFFFFFFFFFFFFFF == f64_to_bits(f) // TODO improve to catch all cases20 const bits = f64_to_bits(f);
21 const exp: i64 = i64((bits >> 52) & ((1 << 11) - 1));
22 const sig = (bits & ((1 << 52) - 1)) | (1 << 52);
23
24 sig != 0 && exp == (1 << 11) - 1
21}25}
2226
23pub fn f64_is_inf(f: f64) -> bool {27pub fn f64_is_inf(f: f64) -> bool {
std/std.zig+138
...@@ -108,6 +108,20 @@ pub struct OutStream {...@@ -108,6 +108,20 @@ pub struct OutStream {
108 return amt_printed;108 return amt_printed;
109 }109 }
110110
111 pub fn print_f64(os: &OutStream, x: f64) -> %isize {
112 if (os.index + max_f64_digits >= os.buffer.len) {
113 %return os.flush();
114 }
115 const amt_printed = buf_print_f64(os.buffer[os.index...], x, 4);
116 os.index += amt_printed;
117
118 if (!os.buffered) {
119 %return os.flush();
120 }
121
122 return amt_printed;
123 }
124
111 pub fn flush(os: &OutStream) -> %void {125 pub fn flush(os: &OutStream) -> %void {
112 const amt_written = write(os.fd, os.buffer.ptr, os.index);126 const amt_written = write(os.fd, os.buffer.ptr, os.index);
113 os.index = 0;127 os.index = 0;
...@@ -229,6 +243,130 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize {...@@ -229,6 +243,130 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize {
229 return len;243 return len;
230}244}
231245
246pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
247 const numExpBits = 11;
248 const numRawSigBits = 52; // not including implicit 1 bit
249 const expBias = 1023;
250
251 var decs = decimals;
252 if (decs >= max_u64_base10_digits) {
253 decs = max_u64_base10_digits - 1;
254 }
255
256 if (x == f64_get_pos_inf()) {
257 const buf2 = "+Inf";
258 @memcpy(&out_buf[0], &buf2[0], buf2.len);
259 return 4;
260 } else if (x == f64_get_neg_inf()) {
261 const buf2 = "-Inf";
262 @memcpy(&out_buf[0], &buf2[0], buf2.len);
263 return 4;
264 } else if (f64_is_nan(x)) {
265 const buf2 = "NaN";
266 @memcpy(&out_buf[0], &buf2[0], buf2.len);
267 return 3;
268 }
269
270 var buf: [max_f64_digits]u8 = undefined;
271
272 var len: isize = 0;
273
274 // 1 sign bit
275 // 11 exponent bits
276 // 52 significand bits (+ 1 implicit always non-zero bit)
277
278 const bits = f64_to_bits(x);
279 if (bits & (1 << 63) != 0) {
280 buf[0] = '-';
281 len += 1;
282 }
283
284 const rexponent: i64 = i64((bits >> numRawSigBits) & ((1 << numExpBits) - 1));
285 const exponent = rexponent - expBias - numRawSigBits;
286
287 if (rexponent == 0) {
288 buf[len] = '0';
289 len += 1;
290 @memcpy(&out_buf[0], &buf[0], len);
291 return len;
292 }
293
294 const sig = (bits & ((1 << numRawSigBits) - 1)) | (1 << numRawSigBits);
295
296 if (exponent >= 0) {
297 // number is an integer
298
299 if (exponent >= 64 - 53) {
300 // use XeX form
301
302 // TODO support printing large floats
303 //len += buf_print_u64(buf[len...], sig << 10);
304 const str = "LARGEF64";
305 @memcpy(&buf[len], &str[0], str.len);
306 len += str.len;
307 } else {
308 // use typical form
309
310 len += buf_print_u64(buf[len...], sig << u64(exponent));
311 buf[len] = '.';
312 len += 1;
313
314 var i: isize = 0;
315 while (i < decs) {
316 buf[len] = '0';
317 len += 1;
318 i += 1;
319 }
320 }
321 } else {
322 // number is not an integer
323
324 // print out whole part
325 len += buf_print_u64(buf[len...], sig >> u64(-exponent));
326 buf[len] = '.';
327 len += 1;
328
329 // print out fractional part
330 // dec_num holds: fractional part * 10 ^ decs
331 var dec_num: u64 = 0;
332
333 var a: isize = 1;
334 var i: isize = 0;
335 while (i < decs + 5) {
336 a *= 10;
337 i += 1;
338 }
339
340 // create a mask: 1's for the fractional part, 0's for whole part
341 var masked_sig = sig & ((1 << u64(-exponent)) - 1);
342 i = -1;
343 while (i >= exponent) {
344 var bit_set = ((1 << u64(i-exponent)) & masked_sig) != 0;
345
346 if (bit_set) {
347 dec_num += usize(a) >> usize(-i);
348 }
349
350 i -= 1;
351 }
352
353 dec_num /= 100000;
354
355 len += decs;
356
357 i = len - 1;
358 while (i >= len - decs) {
359 buf[i] = '0' + u8(dec_num % 10);
360 dec_num /= 10;
361 i -= 1;
362 }
363 }
364
365 @memcpy(&out_buf[0], &buf[0], len);
366
367 len
368}
369
232fn min_isize(x: isize, y: isize) -> isize {370fn min_isize(x: isize, y: isize) -> isize {
233 if (x < y) x else y371 if (x < y) x else y
234}372}