| ... | @@ -108,6 +108,20 @@ pub struct OutStream { | ... | @@ -108,6 +108,20 @@ pub struct OutStream { |
| 108 | return amt_printed; | 108 | return amt_printed; |
| 109 | } | 109 | } |
| 110 | | 110 | |
| | 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,124 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize { | ... | @@ -229,6 +243,124 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize { |
| 229 | return len; | 243 | return len; |
| 230 | } | 244 | } |
| 231 | | 245 | |
| | 246 | pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize { |
| | 247 | var decs = decimals; |
| | 248 | if (decs >= max_u64_base10_digits) { |
| | 249 | decs = max_u64_base10_digits - 1; |
| | 250 | } |
| | 251 | |
| | 252 | if (x == f64_get_pos_inf()) { |
| | 253 | const buf2 = "+Inf"; |
| | 254 | @memcpy(&out_buf[0], &buf2[0], buf2.len); |
| | 255 | return 4; |
| | 256 | } else if (x == f64_get_neg_inf()) { |
| | 257 | const buf2 = "-Inf"; |
| | 258 | @memcpy(&out_buf[0], &buf2[0], buf2.len); |
| | 259 | return 4; |
| | 260 | } else if (f64_is_nan(x)) { |
| | 261 | const buf2 = "NaN"; |
| | 262 | @memcpy(&out_buf[0], &buf2[0], buf2.len); |
| | 263 | return 3; |
| | 264 | } |
| | 265 | |
| | 266 | var buf: [max_f64_digits]u8 = undefined; |
| | 267 | |
| | 268 | var len: isize = 0; |
| | 269 | |
| | 270 | // 1 sign bit |
| | 271 | // 11 exponent bits |
| | 272 | // 52 significand bits (+ 1 implicit always non-zero bit) |
| | 273 | |
| | 274 | const bits = f64_to_bits(x); |
| | 275 | if (bits & (1 << 63) != 0) { |
| | 276 | buf[0] = '-'; |
| | 277 | len += 1; |
| | 278 | } |
| | 279 | |
| | 280 | const rexponent: i64 = i64((bits >> 52) & ((1 << 11) - 1)); |
| | 281 | const exponent = rexponent - 1023 - 52; |
| | 282 | |
| | 283 | if (rexponent == 0) { |
| | 284 | buf[len] = '0'; |
| | 285 | len += 1; |
| | 286 | @memcpy(&out_buf[0], &buf[0], len); |
| | 287 | return len; |
| | 288 | } |
| | 289 | |
| | 290 | const sig = (bits & ((1 << 52) - 1)) | (1 << 52); |
| | 291 | |
| | 292 | if (exponent >= 0) { |
| | 293 | // number is an integer |
| | 294 | |
| | 295 | if (exponent >= 11) { |
| | 296 | // use XeX form |
| | 297 | |
| | 298 | // TODO support printing large floats |
| | 299 | //len += buf_print_u64(buf[len...], sig << 10); |
| | 300 | const str = "LARGEF64"; |
| | 301 | @memcpy(&buf[len], &str[0], str.len); |
| | 302 | len += str.len; |
| | 303 | } else { |
| | 304 | // use typical form |
| | 305 | |
| | 306 | len += buf_print_u64(buf[len...], sig << u64(exponent)); |
| | 307 | buf[len] = '.'; |
| | 308 | len += 1; |
| | 309 | |
| | 310 | var i: isize = 0; |
| | 311 | while (i < decs) { |
| | 312 | buf[len] = '0'; |
| | 313 | len += 1; |
| | 314 | i += 1; |
| | 315 | } |
| | 316 | } |
| | 317 | } else { |
| | 318 | // number is not an integer |
| | 319 | |
| | 320 | // print out whole part |
| | 321 | len += buf_print_u64(buf[len...], sig >> u64(-exponent)); |
| | 322 | buf[len] = '.'; |
| | 323 | len += 1; |
| | 324 | |
| | 325 | // print out fractional part |
| | 326 | // dec_num holds: fractional part * 10 ^ decs |
| | 327 | var dec_num: u64 = 0; |
| | 328 | |
| | 329 | var a: isize = 1; |
| | 330 | var i: isize = 0; |
| | 331 | while (i < decs) { |
| | 332 | a *= 10; |
| | 333 | i += 1; |
| | 334 | } |
| | 335 | |
| | 336 | // create a mask: 1's for the fractional part, 0's for whole part |
| | 337 | var masked_sig = sig & ((1 << u64(-exponent)) - 1); |
| | 338 | i = -1; |
| | 339 | while (i >= exponent) { |
| | 340 | var bit_set = ((1 << u64(i-exponent)) & masked_sig) != 0; |
| | 341 | |
| | 342 | if (bit_set) { |
| | 343 | dec_num += usize(a) >> usize(-i); |
| | 344 | } |
| | 345 | |
| | 346 | i -= 1; |
| | 347 | } |
| | 348 | |
| | 349 | len += decs; |
| | 350 | |
| | 351 | i = len - 1; |
| | 352 | while (i >= len - decs) { |
| | 353 | buf[i] = '0' + u8(dec_num % 10); |
| | 354 | dec_num /= 10; |
| | 355 | i -= 1; |
| | 356 | } |
| | 357 | } |
| | 358 | |
| | 359 | @memcpy(&out_buf[0], &buf[0], len); |
| | 360 | |
| | 361 | len |
| | 362 | } |
| | 363 | |
| 232 | fn min_isize(x: isize, y: isize) -> isize { | 364 | fn min_isize(x: isize, y: isize) -> isize { |
| 233 | if (x < y) x else y | 365 | if (x < y) x else y |
| 234 | } | 366 | } |