| ... | ... | @@ -108,6 +108,20 @@ pub struct OutStream { |
| 108 | 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 | 125 | pub fn flush(os: &OutStream) -> %void { |
| 112 | 126 | const amt_written = write(os.fd, os.buffer.ptr, os.index); |
| 113 | 127 | os.index = 0; |
| ... | ... | @@ -229,6 +243,130 @@ pub fn buf_print_u64(out_buf: []u8, x: u64) -> isize { |
| 229 | 243 | return len; |
| 230 | 244 | } |
| 231 | 245 | |
| 246 | pub 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 | |
| 232 | 370 | fn min_isize(x: isize, y: isize) -> isize { |
| 233 | 371 | if (x < y) x else y |
| 234 | 372 | } |