Skip to content

Commit da33258

Browse files
Restore leading zero in exponent for printf("%e") and printf("%g") (#14695)
1 parent b08f4a2 commit da33258

File tree

2 files changed

+112
-104
lines changed

2 files changed

+112
-104
lines changed

spec/std/sprintf_spec.cr

Lines changed: 102 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -411,60 +411,60 @@ describe "::sprintf" do
411411

412412
context "scientific format" do
413413
it "works" do
414-
assert_sprintf "%e", 123.45, "1.234500e+2"
415-
assert_sprintf "%E", 123.45, "1.234500E+2"
414+
assert_sprintf "%e", 123.45, "1.234500e+02"
415+
assert_sprintf "%E", 123.45, "1.234500E+02"
416416

417417
assert_sprintf "%e", Float64::MAX, "1.797693e+308"
418418
assert_sprintf "%e", Float64::MIN_POSITIVE, "2.225074e-308"
419419
assert_sprintf "%e", Float64::MIN_SUBNORMAL, "4.940656e-324"
420-
assert_sprintf "%e", 0.0, "0.000000e+0"
421-
assert_sprintf "%e", -0.0, "-0.000000e+0"
420+
assert_sprintf "%e", 0.0, "0.000000e+00"
421+
assert_sprintf "%e", -0.0, "-0.000000e+00"
422422
assert_sprintf "%e", -Float64::MIN_SUBNORMAL, "-4.940656e-324"
423423
assert_sprintf "%e", -Float64::MIN_POSITIVE, "-2.225074e-308"
424424
assert_sprintf "%e", Float64::MIN, "-1.797693e+308"
425425
end
426426

427427
context "width specifier" do
428428
it "sets the minimum length of the string" do
429-
assert_sprintf "%20e", 123.45, " 1.234500e+2"
430-
assert_sprintf "%20e", -123.45, " -1.234500e+2"
431-
assert_sprintf "%+20e", 123.45, " +1.234500e+2"
429+
assert_sprintf "%20e", 123.45, " 1.234500e+02"
430+
assert_sprintf "%20e", -123.45, " -1.234500e+02"
431+
assert_sprintf "%+20e", 123.45, " +1.234500e+02"
432432

433-
assert_sprintf "%12e", 123.45, " 1.234500e+2"
434-
assert_sprintf "%12e", -123.45, "-1.234500e+2"
435-
assert_sprintf "%+12e", 123.45, "+1.234500e+2"
433+
assert_sprintf "%13e", 123.45, " 1.234500e+02"
434+
assert_sprintf "%13e", -123.45, "-1.234500e+02"
435+
assert_sprintf "%+13e", 123.45, "+1.234500e+02"
436436

437-
assert_sprintf "%11e", 123.45, "1.234500e+2"
438-
assert_sprintf "%11e", -123.45, "-1.234500e+2"
439-
assert_sprintf "%+11e", 123.45, "+1.234500e+2"
437+
assert_sprintf "%12e", 123.45, "1.234500e+02"
438+
assert_sprintf "%12e", -123.45, "-1.234500e+02"
439+
assert_sprintf "%+12e", 123.45, "+1.234500e+02"
440440

441-
assert_sprintf "%2e", 123.45, "1.234500e+2"
442-
assert_sprintf "%2e", -123.45, "-1.234500e+2"
443-
assert_sprintf "%+2e", 123.45, "+1.234500e+2"
441+
assert_sprintf "%2e", 123.45, "1.234500e+02"
442+
assert_sprintf "%2e", -123.45, "-1.234500e+02"
443+
assert_sprintf "%+2e", 123.45, "+1.234500e+02"
444444
end
445445

446446
it "left-justifies on negative width" do
447-
assert_sprintf "%*e", [-20, 123.45], "1.234500e+2 "
447+
assert_sprintf "%*e", [-20, 123.45], "1.234500e+02 "
448448
end
449449
end
450450

451451
context "precision specifier" do
452452
it "sets the minimum length of the fractional part" do
453-
assert_sprintf "%.0e", 2.0, "2e+0"
454-
assert_sprintf "%.0e", 2.5.prev_float, "2e+0"
455-
assert_sprintf "%.0e", 2.5, "2e+0"
456-
assert_sprintf "%.0e", 2.5.next_float, "3e+0"
457-
assert_sprintf "%.0e", 3.0, "3e+0"
458-
assert_sprintf "%.0e", 3.5.prev_float, "3e+0"
459-
assert_sprintf "%.0e", 3.5, "4e+0"
460-
assert_sprintf "%.0e", 3.5.next_float, "4e+0"
461-
assert_sprintf "%.0e", 4.0, "4e+0"
453+
assert_sprintf "%.0e", 2.0, "2e+00"
454+
assert_sprintf "%.0e", 2.5.prev_float, "2e+00"
455+
assert_sprintf "%.0e", 2.5, "2e+00"
456+
assert_sprintf "%.0e", 2.5.next_float, "3e+00"
457+
assert_sprintf "%.0e", 3.0, "3e+00"
458+
assert_sprintf "%.0e", 3.5.prev_float, "3e+00"
459+
assert_sprintf "%.0e", 3.5, "4e+00"
460+
assert_sprintf "%.0e", 3.5.next_float, "4e+00"
461+
assert_sprintf "%.0e", 4.0, "4e+00"
462462

463-
assert_sprintf "%.0e", 9.5, "1e+1"
463+
assert_sprintf "%.0e", 9.5, "1e+01"
464464

465-
assert_sprintf "%.100e", 1.1, "1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000e+0"
465+
assert_sprintf "%.100e", 1.1, "1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000e+00"
466466

467-
assert_sprintf "%.10000e", 1.0, "1.#{"0" * 10000}e+0"
467+
assert_sprintf "%.10000e", 1.0, "1.#{"0" * 10000}e+00"
468468

469469
assert_sprintf "%.1000e", Float64::MIN_POSITIVE.prev_float,
470470
"2.2250738585072008890245868760858598876504231122409594654935248025624400092282356951" \
@@ -482,103 +482,103 @@ describe "::sprintf" do
482482
end
483483

484484
it "can be used with width" do
485-
assert_sprintf "%20.12e", 123.45, " 1.234500000000e+2"
486-
assert_sprintf "%20.12e", -123.45, " -1.234500000000e+2"
487-
assert_sprintf "%20.12e", 0.0, " 0.000000000000e+0"
485+
assert_sprintf "%20.13e", 123.45, " 1.2345000000000e+02"
486+
assert_sprintf "%20.13e", -123.45, "-1.2345000000000e+02"
487+
assert_sprintf "%20.13e", 0.0, " 0.0000000000000e+00"
488488

489-
assert_sprintf "%-20.12e", 123.45, "1.234500000000e+2 "
490-
assert_sprintf "%-20.12e", -123.45, "-1.234500000000e+2 "
491-
assert_sprintf "%-20.12e", 0.0, "0.000000000000e+0 "
489+
assert_sprintf "%-20.13e", 123.45, "1.2345000000000e+02 "
490+
assert_sprintf "%-20.13e", -123.45, "-1.2345000000000e+02"
491+
assert_sprintf "%-20.13e", 0.0, "0.0000000000000e+00 "
492492

493-
assert_sprintf "%8.12e", 123.45, "1.234500000000e+2"
494-
assert_sprintf "%8.12e", -123.45, "-1.234500000000e+2"
495-
assert_sprintf "%8.12e", 0.0, "0.000000000000e+0"
493+
assert_sprintf "%8.13e", 123.45, "1.2345000000000e+02"
494+
assert_sprintf "%8.13e", -123.45, "-1.2345000000000e+02"
495+
assert_sprintf "%8.13e", 0.0, "0.0000000000000e+00"
496496
end
497497

498498
it "is ignored if precision argument is negative" do
499-
assert_sprintf "%.*e", [-2, 123.45], "1.234500e+2"
499+
assert_sprintf "%.*e", [-2, 123.45], "1.234500e+02"
500500
end
501501
end
502502

503503
context "sharp flag" do
504504
it "prints a decimal point even if no digits follow" do
505-
assert_sprintf "%#.0e", 1.0, "1.e+0"
506-
assert_sprintf "%#.0e", 10000.0, "1.e+4"
505+
assert_sprintf "%#.0e", 1.0, "1.e+00"
506+
assert_sprintf "%#.0e", 10000.0, "1.e+04"
507507
assert_sprintf "%#.0e", 1.0e+23, "1.e+23"
508508
assert_sprintf "%#.0e", 1.0e-100, "1.e-100"
509-
assert_sprintf "%#.0e", 0.0, "0.e+0"
510-
assert_sprintf "%#.0e", -0.0, "-0.e+0"
509+
assert_sprintf "%#.0e", 0.0, "0.e+00"
510+
assert_sprintf "%#.0e", -0.0, "-0.e+00"
511511
end
512512
end
513513

514514
context "plus flag" do
515515
it "writes a plus sign for positive values" do
516-
assert_sprintf "%+e", 123.45, "+1.234500e+2"
517-
assert_sprintf "%+e", -123.45, "-1.234500e+2"
518-
assert_sprintf "%+e", 0.0, "+0.000000e+0"
516+
assert_sprintf "%+e", 123.45, "+1.234500e+02"
517+
assert_sprintf "%+e", -123.45, "-1.234500e+02"
518+
assert_sprintf "%+e", 0.0, "+0.000000e+00"
519519
end
520520

521521
it "writes plus sign after left space-padding" do
522-
assert_sprintf "%+20e", 123.45, " +1.234500e+2"
523-
assert_sprintf "%+20e", -123.45, " -1.234500e+2"
524-
assert_sprintf "%+20e", 0.0, " +0.000000e+0"
522+
assert_sprintf "%+20e", 123.45, " +1.234500e+02"
523+
assert_sprintf "%+20e", -123.45, " -1.234500e+02"
524+
assert_sprintf "%+20e", 0.0, " +0.000000e+00"
525525
end
526526

527527
it "writes plus sign before left zero-padding" do
528-
assert_sprintf "%+020e", 123.45, "+000000001.234500e+2"
529-
assert_sprintf "%+020e", -123.45, "-000000001.234500e+2"
530-
assert_sprintf "%+020e", 0.0, "+000000000.000000e+0"
528+
assert_sprintf "%+020e", 123.45, "+00000001.234500e+02"
529+
assert_sprintf "%+020e", -123.45, "-00000001.234500e+02"
530+
assert_sprintf "%+020e", 0.0, "+00000000.000000e+00"
531531
end
532532
end
533533

534534
context "space flag" do
535535
it "writes a space for positive values" do
536-
assert_sprintf "% e", 123.45, " 1.234500e+2"
537-
assert_sprintf "% e", -123.45, "-1.234500e+2"
538-
assert_sprintf "% e", 0.0, " 0.000000e+0"
536+
assert_sprintf "% e", 123.45, " 1.234500e+02"
537+
assert_sprintf "% e", -123.45, "-1.234500e+02"
538+
assert_sprintf "% e", 0.0, " 0.000000e+00"
539539
end
540540

541541
it "writes space before left space-padding" do
542-
assert_sprintf "% 20e", 123.45, " 1.234500e+2"
543-
assert_sprintf "% 20e", -123.45, " -1.234500e+2"
544-
assert_sprintf "% 20e", 0.0, " 0.000000e+0"
542+
assert_sprintf "% 20e", 123.45, " 1.234500e+02"
543+
assert_sprintf "% 20e", -123.45, " -1.234500e+02"
544+
assert_sprintf "% 20e", 0.0, " 0.000000e+00"
545545

546-
assert_sprintf "% 020e", 123.45, " 000000001.234500e+2"
547-
assert_sprintf "% 020e", -123.45, "-000000001.234500e+2"
548-
assert_sprintf "% 020e", 0.0, " 000000000.000000e+0"
546+
assert_sprintf "% 020e", 123.45, " 00000001.234500e+02"
547+
assert_sprintf "% 020e", -123.45, "-00000001.234500e+02"
548+
assert_sprintf "% 020e", 0.0, " 00000000.000000e+00"
549549
end
550550

551551
it "is ignored if plus flag is also specified" do
552-
assert_sprintf "% +e", 123.45, "+1.234500e+2"
553-
assert_sprintf "%+ e", -123.45, "-1.234500e+2"
552+
assert_sprintf "% +e", 123.45, "+1.234500e+02"
553+
assert_sprintf "%+ e", -123.45, "-1.234500e+02"
554554
end
555555
end
556556

557557
context "zero flag" do
558558
it "left-pads the result with zeros" do
559-
assert_sprintf "%020e", 123.45, "0000000001.234500e+2"
560-
assert_sprintf "%020e", -123.45, "-000000001.234500e+2"
561-
assert_sprintf "%020e", 0.0, "0000000000.000000e+0"
559+
assert_sprintf "%020e", 123.45, "000000001.234500e+02"
560+
assert_sprintf "%020e", -123.45, "-00000001.234500e+02"
561+
assert_sprintf "%020e", 0.0, "000000000.000000e+00"
562562
end
563563

564564
it "is ignored if string is left-justified" do
565-
assert_sprintf "%-020e", 123.45, "1.234500e+2 "
566-
assert_sprintf "%-020e", -123.45, "-1.234500e+2 "
567-
assert_sprintf "%-020e", 0.0, "0.000000e+0 "
565+
assert_sprintf "%-020e", 123.45, "1.234500e+02 "
566+
assert_sprintf "%-020e", -123.45, "-1.234500e+02 "
567+
assert_sprintf "%-020e", 0.0, "0.000000e+00 "
568568
end
569569

570570
it "can be used with precision" do
571-
assert_sprintf "%020.12e", 123.45, "0001.234500000000e+2"
572-
assert_sprintf "%020.12e", -123.45, "-001.234500000000e+2"
573-
assert_sprintf "%020.12e", 0.0, "0000.000000000000e+0"
571+
assert_sprintf "%020.12e", 123.45, "001.234500000000e+02"
572+
assert_sprintf "%020.12e", -123.45, "-01.234500000000e+02"
573+
assert_sprintf "%020.12e", 0.0, "000.000000000000e+00"
574574
end
575575
end
576576

577577
context "minus flag" do
578578
it "left-justifies the string" do
579-
assert_sprintf "%-20e", 123.45, "1.234500e+2 "
580-
assert_sprintf "%-20e", -123.45, "-1.234500e+2 "
581-
assert_sprintf "%-20e", 0.0, "0.000000e+0 "
579+
assert_sprintf "%-20e", 123.45, "1.234500e+02 "
580+
assert_sprintf "%-20e", -123.45, "-1.234500e+02 "
581+
assert_sprintf "%-20e", 0.0, "0.000000e+00 "
582582
end
583583
end
584584
end
@@ -588,8 +588,8 @@ describe "::sprintf" do
588588
assert_sprintf "%g", 123.45, "123.45"
589589
assert_sprintf "%G", 123.45, "123.45"
590590

591-
assert_sprintf "%g", 1.2345e-5, "1.2345e-5"
592-
assert_sprintf "%G", 1.2345e-5, "1.2345E-5"
591+
assert_sprintf "%g", 1.2345e-5, "1.2345e-05"
592+
assert_sprintf "%G", 1.2345e-5, "1.2345E-05"
593593

594594
assert_sprintf "%g", 1.2345e+25, "1.2345e+25"
595595
assert_sprintf "%G", 1.2345e+25, "1.2345E+25"
@@ -630,9 +630,9 @@ describe "::sprintf" do
630630

631631
context "precision specifier" do
632632
it "sets the precision of the value" do
633-
assert_sprintf "%.0g", 123.45, "1e+2"
634-
assert_sprintf "%.1g", 123.45, "1e+2"
635-
assert_sprintf "%.2g", 123.45, "1.2e+2"
633+
assert_sprintf "%.0g", 123.45, "1e+02"
634+
assert_sprintf "%.1g", 123.45, "1e+02"
635+
assert_sprintf "%.2g", 123.45, "1.2e+02"
636636
assert_sprintf "%.3g", 123.45, "123"
637637
assert_sprintf "%.4g", 123.45, "123.5"
638638
assert_sprintf "%.5g", 123.45, "123.45"
@@ -650,41 +650,41 @@ describe "::sprintf" do
650650
assert_sprintf "%.5g", 1.23e-45, "1.23e-45"
651651
assert_sprintf "%.6g", 1.23e-45, "1.23e-45"
652652

653-
assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-5"
653+
assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-05"
654654
end
655655

656656
it "can be used with width" do
657-
assert_sprintf "%10.1g", 123.45, " 1e+2"
658-
assert_sprintf "%10.2g", 123.45, " 1.2e+2"
657+
assert_sprintf "%10.1g", 123.45, " 1e+02"
658+
assert_sprintf "%10.2g", 123.45, " 1.2e+02"
659659
assert_sprintf "%10.3g", 123.45, " 123"
660660
assert_sprintf "%10.4g", 123.45, " 123.5"
661661
assert_sprintf "%10.5g", 123.45, " 123.45"
662-
assert_sprintf "%10.1g", -123.45, " -1e+2"
663-
assert_sprintf "%10.2g", -123.45, " -1.2e+2"
662+
assert_sprintf "%10.1g", -123.45, " -1e+02"
663+
assert_sprintf "%10.2g", -123.45, " -1.2e+02"
664664
assert_sprintf "%10.3g", -123.45, " -123"
665665
assert_sprintf "%10.4g", -123.45, " -123.5"
666666
assert_sprintf "%10.5g", -123.45, " -123.45"
667667
assert_sprintf "%10.5g", 0, " 0"
668668

669-
assert_sprintf "%-10.1g", 123.45, "1e+2 "
670-
assert_sprintf "%-10.2g", 123.45, "1.2e+2 "
669+
assert_sprintf "%-10.1g", 123.45, "1e+02 "
670+
assert_sprintf "%-10.2g", 123.45, "1.2e+02 "
671671
assert_sprintf "%-10.3g", 123.45, "123 "
672672
assert_sprintf "%-10.4g", 123.45, "123.5 "
673673
assert_sprintf "%-10.5g", 123.45, "123.45 "
674-
assert_sprintf "%-10.1g", -123.45, "-1e+2 "
675-
assert_sprintf "%-10.2g", -123.45, "-1.2e+2 "
674+
assert_sprintf "%-10.1g", -123.45, "-1e+02 "
675+
assert_sprintf "%-10.2g", -123.45, "-1.2e+02 "
676676
assert_sprintf "%-10.3g", -123.45, "-123 "
677677
assert_sprintf "%-10.4g", -123.45, "-123.5 "
678678
assert_sprintf "%-10.5g", -123.45, "-123.45 "
679679
assert_sprintf "%-10.5g", 0, "0 "
680680

681-
assert_sprintf "%3.1g", 123.45, "1e+2"
682-
assert_sprintf "%3.2g", 123.45, "1.2e+2"
681+
assert_sprintf "%3.1g", 123.45, "1e+02"
682+
assert_sprintf "%3.2g", 123.45, "1.2e+02"
683683
assert_sprintf "%3.3g", 123.45, "123"
684684
assert_sprintf "%3.4g", 123.45, "123.5"
685685
assert_sprintf "%3.5g", 123.45, "123.45"
686-
assert_sprintf "%3.1g", -123.45, "-1e+2"
687-
assert_sprintf "%3.2g", -123.45, "-1.2e+2"
686+
assert_sprintf "%3.1g", -123.45, "-1e+02"
687+
assert_sprintf "%3.2g", -123.45, "-1.2e+02"
688688
assert_sprintf "%3.3g", -123.45, "-123"
689689
assert_sprintf "%3.4g", -123.45, "-123.5"
690690
assert_sprintf "%3.5g", -123.45, "-123.45"
@@ -699,19 +699,19 @@ describe "::sprintf" do
699699

700700
context "sharp flag" do
701701
it "prints decimal point and trailing zeros" do
702-
assert_sprintf "%#.0g", 12345, "1.e+4"
702+
assert_sprintf "%#.0g", 12345, "1.e+04"
703703
assert_sprintf "%#.6g", 12345, "12345.0"
704704
assert_sprintf "%#.10g", 12345, "12345.00000"
705705
assert_sprintf "%#.100g", 12345, "12345.#{"0" * 95}"
706706
assert_sprintf "%#.1000g", 12345, "12345.#{"0" * 995}"
707707

708-
assert_sprintf "%#.0g", 1e-5, "1.e-5"
709-
assert_sprintf "%#.6g", 1e-5, "1.00000e-5"
710-
assert_sprintf "%#.10g", 1e-5, "1.000000000e-5"
711-
assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-5"
712-
assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-5"
708+
assert_sprintf "%#.0g", 1e-5, "1.e-05"
709+
assert_sprintf "%#.6g", 1e-5, "1.00000e-05"
710+
assert_sprintf "%#.10g", 1e-5, "1.000000000e-05"
711+
assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-05"
712+
assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-05"
713713

714-
assert_sprintf "%#15.0g", 12345, " 1.e+4"
714+
assert_sprintf "%#15.0g", 12345, " 1.e+04"
715715
assert_sprintf "%#15.6g", 12345, " 12345.0"
716716
assert_sprintf "%#15.10g", 12345, " 12345.00000"
717717
end
@@ -774,8 +774,8 @@ describe "::sprintf" do
774774
end
775775

776776
it "can be used with precision" do
777-
assert_sprintf "%010.2g", 123.45, "00001.2e+2"
778-
assert_sprintf "%010.2g", -123.45, "-0001.2e+2"
777+
assert_sprintf "%010.2g", 123.45, "0001.2e+02"
778+
assert_sprintf "%010.2g", -123.45, "-001.2e+02"
779779
assert_sprintf "%010.2g", 0.0, "0000000000"
780780
end
781781
end

src/string/formatter.cr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ struct String::Formatter(A)
430430
str_size = printf_size + trailing_zeros
431431
str_size += 1 if sign < 0 || flags.plus || flags.space
432432
str_size += 1 if flags.sharp && dot_index.nil?
433+
str_size += 1 if printf_slice.size - e_index < 4
433434

434435
pad(str_size, flags) if flags.left_padding? && flags.padding_char != '0'
435436

@@ -441,7 +442,9 @@ struct String::Formatter(A)
441442
@io.write_string(printf_slice[0, e_index])
442443
trailing_zeros.times { @io << '0' }
443444
@io << '.' if flags.sharp && dot_index.nil?
444-
@io.write_string(printf_slice[e_index..])
445+
@io.write_string(printf_slice[e_index, 2])
446+
@io << '0' if printf_slice.size - e_index < 4
447+
@io.write_string(printf_slice[(e_index + 2)..])
445448

446449
pad(str_size, flags) if flags.right_padding?
447450
end
@@ -465,6 +468,7 @@ struct String::Formatter(A)
465468
str_size = printf_size
466469
str_size += 1 if sign < 0 || flags.plus || flags.space
467470
str_size += (dot_index.nil? ? 1 : 0) + trailing_zeros if flags.sharp
471+
str_size += 1 if printf_slice.size - e_index < 4 if e_index
468472

469473
pad(str_size, flags) if flags.left_padding? && flags.padding_char != '0'
470474

@@ -476,7 +480,11 @@ struct String::Formatter(A)
476480
@io.write_string(printf_slice[0...e_index])
477481
trailing_zeros.times { @io << '0' } if flags.sharp
478482
@io << '.' if flags.sharp && dot_index.nil?
479-
@io.write_string(printf_slice[e_index..]) if e_index
483+
if e_index
484+
@io.write_string(printf_slice[e_index, 2])
485+
@io << '0' if printf_slice.size - e_index < 4
486+
@io.write_string(printf_slice[(e_index + 2)..])
487+
end
480488

481489
pad(str_size, flags) if flags.right_padding?
482490
end

0 commit comments

Comments
 (0)