|
4 | 4 |
|
5 | 5 | package fmt |
6 | 6 |
|
| 7 | +import "strconv" |
| 8 | + |
7 | 9 | /* |
8 | 10 | Raw formatter. See print.go for a more palatable interface. |
9 | 11 |
|
@@ -181,7 +183,7 @@ func (f *Fmt) d64(a int64) *Fmt { |
181 | 183 | f.clearflags(); |
182 | 184 | return f; |
183 | 185 | } |
184 | | - |
| 186 | + |
185 | 187 | func (f *Fmt) d32(a int32) *Fmt { |
186 | 188 | return f.d64(int64(a)); |
187 | 189 | } |
@@ -332,227 +334,82 @@ func (f *Fmt) s(s string) *Fmt { |
332 | 334 | return f; |
333 | 335 | } |
334 | 336 |
|
335 | | -func pow10(n int) float64 { |
336 | | - var d float64; |
337 | | - |
338 | | - neg := false; |
339 | | - if n < 0 { |
340 | | - if n < -307 { // DBL_MIN_10_EXP |
341 | | - return 0.; |
342 | | - } |
343 | | - neg = true; |
344 | | - n = -n; |
345 | | - }else if n > 308 { // DBL_MAX_10_EXP |
346 | | - return 1.79769e+308; // HUGE_VAL |
347 | | - } |
| 337 | +// floating-point |
348 | 338 |
|
349 | | - if n < NPows10 { |
350 | | - d = pows10[n]; |
351 | | - } else { |
352 | | - d = pows10[NPows10-1]; |
353 | | - for { |
354 | | - n -= NPows10 - 1; |
355 | | - if n < NPows10 { |
356 | | - d *= pows10[n]; |
357 | | - break; |
358 | | - } |
359 | | - d *= pows10[NPows10 - 1]; |
360 | | - } |
361 | | - } |
362 | | - if neg { |
363 | | - return 1/d; |
364 | | - } |
365 | | - return d; |
366 | | -} |
367 | | - |
368 | | -func unpack(a float64) (negative bool, exp int, num float64) { |
369 | | - if a == 0 { |
370 | | - return false, 0, 0.0 |
371 | | - } |
372 | | - neg := a < 0; |
373 | | - if neg { |
374 | | - a = -a; |
375 | | - } |
376 | | - // find g,e such that a = g*10^e. |
377 | | - // guess 10-exponent using 2-exponent, then fine tune. |
378 | | - g, e2 := sys.frexp(a); |
379 | | - e := int(float64(e2) * .301029995663981); |
380 | | - g = a * pow10(-e); |
381 | | - for g < 1 { |
382 | | - e--; |
383 | | - g = a * pow10(-e); |
384 | | - } |
385 | | - for g >= 10 { |
386 | | - e++; |
387 | | - g = a * pow10(-e); |
388 | | - } |
389 | | - return neg, e, g; |
390 | | -} |
391 | | - |
392 | | -// check for Inf, NaN |
393 | | -func(f *Fmt) InfOrNan(a float64) bool { |
394 | | - if sys.isInf(a, 0) { |
395 | | - if sys.isInf(a, 1) { |
396 | | - f.pad("Inf"); |
397 | | - } else { |
398 | | - f.pad("-Inf"); |
399 | | - } |
400 | | - f.clearflags(); |
401 | | - return true; |
402 | | - } |
403 | | - if sys.isNaN(a) { |
404 | | - f.pad("NaN"); |
405 | | - f.clearflags(); |
406 | | - return true; |
| 339 | +func Prec(f *Fmt, def int) int { |
| 340 | + if f.prec_present { |
| 341 | + return f.prec; |
407 | 342 | } |
408 | | - return false; |
| 343 | + return def; |
409 | 344 | } |
410 | 345 |
|
411 | | -// float64 |
412 | | -func (f *Fmt) e64(a float64) *Fmt { |
413 | | - var negative bool; |
414 | | - var g float64; |
415 | | - var exp int; |
416 | | - if f.InfOrNan(a) { |
417 | | - return f; |
418 | | - } |
419 | | - negative, exp, g = unpack(a); |
420 | | - prec := 6; |
421 | | - if f.prec_present { |
422 | | - prec = f.prec; |
423 | | - } |
424 | | - prec++; // one digit left of decimal |
425 | | - var s string; |
426 | | - // multiply by 10^prec to get decimal places; put decimal after first digit |
427 | | - if g == 0 { |
428 | | - // doesn't work for zero - fake it |
429 | | - s = "000000000000000000000000000000000000000000000000000000000000"; |
430 | | - if prec < len(s) { |
431 | | - s = s[0:prec]; |
432 | | - } else { |
433 | | - prec = len(s); |
434 | | - } |
435 | | - } else { |
436 | | - g *= pow10(prec); |
437 | | - s = f.integer(int64(g + .5), 10, true, &ldigits); // get the digits into a string |
438 | | - } |
439 | | - s = s[0:1] + "." + s[1:prec]; // insert a decimal point |
440 | | - // print exponent with leading 0 if appropriate. |
441 | | - es := New().p(2).integer(int64(exp), 10, true, &ldigits); |
442 | | - if exp >= 0 { |
443 | | - es = "+" + es; // TODO: should do this with a fmt flag |
444 | | - } |
445 | | - s = s + "e" + es; |
446 | | - if negative { |
447 | | - s = "-" + s; |
448 | | - } |
| 346 | +func FmtString(f *Fmt, s string) *Fmt { |
449 | 347 | f.pad(s); |
450 | 348 | f.clearflags(); |
451 | 349 | return f; |
452 | 350 | } |
453 | 351 |
|
454 | 352 | // float64 |
| 353 | +func (f *Fmt) e64(a float64) *Fmt { |
| 354 | + return FmtString(f, strconv.ftoa64(a, 'e', Prec(f, 6))); |
| 355 | +} |
| 356 | + |
455 | 357 | func (f *Fmt) f64(a float64) *Fmt { |
456 | | - var negative bool; |
457 | | - var g float64; |
458 | | - var exp int; |
459 | | - if f.InfOrNan(a) { |
460 | | - return f; |
461 | | - } |
462 | | - negative, exp, g = unpack(a); |
463 | | - if exp > 19 || exp < -19 { // too big for this sloppy code |
464 | | - return f.e64(a); |
465 | | - } |
466 | | - prec := 6; |
467 | | - if f.prec_present { |
468 | | - prec = f.prec; |
469 | | - } |
470 | | - // prec is number of digits after decimal point |
471 | | - s := "NO"; |
472 | | - if exp >= 0 { |
473 | | - g *= pow10(exp); |
474 | | - gi := int64(g); |
475 | | - s = New().integer(gi, 10, true, &ldigits); |
476 | | - s = s + "."; |
477 | | - g -= float64(gi); |
478 | | - s = s + New().p(prec).integer(int64(g*pow10(prec) + .5), 10, true, &ldigits); |
479 | | - } else { |
480 | | - g *= pow10(prec + exp); |
481 | | - s = "0." + New().p(prec).integer(int64(g + .5), 10, true, &ldigits); |
482 | | - } |
483 | | - if negative { |
484 | | - s = "-" + s; |
485 | | - } |
486 | | - f.pad(s); |
487 | | - f.clearflags(); |
488 | | - return f; |
| 358 | + return FmtString(f, strconv.ftoa64(a, 'f', Prec(f, 6))); |
489 | 359 | } |
490 | 360 |
|
491 | | -// float64 |
492 | 361 | func (f *Fmt) g64(a float64) *Fmt { |
493 | | - if f.InfOrNan(a) { |
494 | | - return f; |
495 | | - } |
496 | | - f1 := New(); |
497 | | - f2 := New(); |
498 | | - if f.wid_present { |
499 | | - f1.w(f.wid); |
500 | | - f2.w(f.wid); |
501 | | - } |
502 | | - if f.prec_present { |
503 | | - f1.p(f.prec); |
504 | | - f2.p(f.prec); |
505 | | - } |
506 | | - efmt := f1.e64(a).str(); |
507 | | - ffmt := f2.f64(a).str(); |
508 | | - // ffmt can return e in my bogus world; don't trim trailing 0s if so. |
509 | | - f_is_e := false; |
510 | | - for i := 0; i < len(ffmt); i++ { |
511 | | - if ffmt[i] == 'e' { |
512 | | - f_is_e = true; |
513 | | - break; |
514 | | - } |
515 | | - } |
516 | | - if !f_is_e { |
517 | | - // strip trailing zeros |
518 | | - l := len(ffmt); |
519 | | - for ffmt[l-1]=='0' { |
520 | | - l--; |
521 | | - } |
522 | | - ffmt = ffmt[0:l]; |
523 | | - } |
524 | | - if len(efmt) < len(ffmt) { |
525 | | - f.pad(efmt); |
526 | | - } else { |
527 | | - f.pad(ffmt); |
528 | | - } |
529 | | - f.clearflags(); |
530 | | - return f; |
| 362 | + return FmtString(f, strconv.ftoa64(a, 'g', Prec(f, -1))); |
531 | 363 | } |
532 | 364 |
|
533 | | -// float |
534 | | -func (x *Fmt) f32(a float32) *Fmt { |
535 | | - return x.f64(float64(a)) |
| 365 | +func (f *Fmt) fb64(a float64) *Fmt { |
| 366 | + return FmtString(f, strconv.ftoa64(a, 'b', 0)); |
536 | 367 | } |
537 | 368 |
|
538 | | -func (x *Fmt) f(a float) *Fmt { |
539 | | - return x.f64(float64(a)) |
| 369 | +// float32 |
| 370 | +// cannot defer to float64 versions |
| 371 | +// because it will get rounding wrong in corner cases. |
| 372 | +func (f *Fmt) e32(a float32) *Fmt { |
| 373 | + return FmtString(f, strconv.ftoa32(a, 'e', Prec(f, -1))); |
| 374 | +} |
| 375 | + |
| 376 | +func (f *Fmt) f32(a float32) *Fmt { |
| 377 | + return FmtString(f, strconv.ftoa32(a, 'f', Prec(f, 6))); |
| 378 | +} |
| 379 | + |
| 380 | +func (f *Fmt) g32(a float32) *Fmt { |
| 381 | + return FmtString(f, strconv.ftoa32(a, 'g', Prec(f, -1))); |
| 382 | +} |
| 383 | + |
| 384 | +func (f *Fmt) fb32(a float32) *Fmt { |
| 385 | + return FmtString(f, strconv.ftoa32(a, 'b', 0)); |
540 | 386 | } |
541 | 387 |
|
542 | 388 | // float |
543 | | -func (x *Fmt) e32(a float32) *Fmt { |
544 | | - return x.e64(float64(a)) |
| 389 | +func (x *Fmt) f(a float) *Fmt { |
| 390 | + if strconv.floatsize == 32 { |
| 391 | + return x.f32(float32(a)) |
| 392 | + } |
| 393 | + return x.f64(float64(a)) |
545 | 394 | } |
546 | 395 |
|
547 | 396 | func (x *Fmt) e(a float) *Fmt { |
| 397 | + if strconv.floatsize == 32 { |
| 398 | + return x.e32(float32(a)) |
| 399 | + } |
548 | 400 | return x.e64(float64(a)) |
549 | 401 | } |
550 | 402 |
|
551 | | -// float |
552 | | -func (x *Fmt) g32(a float32) *Fmt { |
| 403 | +func (x *Fmt) g(a float) *Fmt { |
| 404 | + if strconv.floatsize == 32 { |
| 405 | + return x.g32(float32(a)) |
| 406 | + } |
553 | 407 | return x.g64(float64(a)) |
554 | 408 | } |
555 | 409 |
|
556 | | -func (x *Fmt) g(a float) *Fmt { |
557 | | - return x.g64(float64(a)) |
| 410 | +func (x *Fmt) fb(a float) *Fmt { |
| 411 | + if strconv.floatsize == 32 { |
| 412 | + return x.fb32(float32(a)) |
| 413 | + } |
| 414 | + return x.fb64(float64(a)) |
558 | 415 | } |
0 commit comments