Skip to content

Commit 675503c

Browse files
committed
math/big: add %x float format
big.Float already had %p for printing hex format, but that format normalizes differently from fmt's %x and ignores precision entirely. This CL adds %x to big.Float, matching fmt's behavior: the verb is spelled 'x' not 'p', the mantissa is normalized to [1, 2), and precision is respected. See golang.org/design/19308-number-literals for background. For #29008. Change-Id: I9c1b9612107094856797e5b0b584c556c1914895 Reviewed-on: https://go-review.googlesource.com/c/160249 Reviewed-by: Robert Griesemer <[email protected]>
1 parent 1e58bb1 commit 675503c

File tree

2 files changed

+229
-102
lines changed

2 files changed

+229
-102
lines changed

src/math/big/floatconv_test.go

Lines changed: 140 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ func TestFloat64Text(t *testing.T) {
268268
{32, 'g', -1, "32"},
269269
{32, 'g', 0, "3e+01"},
270270

271-
// {100, 'x', -1, "%x"},
271+
{100, 'x', -1, "0x1.9p+06"},
272272

273273
// {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
274274
// {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
@@ -339,115 +339,166 @@ func actualPrec(x float64) uint {
339339
}
340340

341341
func TestFloatText(t *testing.T) {
342+
const defaultRound = ^RoundingMode(0)
343+
342344
for _, test := range []struct {
343345
x string
346+
round RoundingMode
344347
prec uint
345348
format byte
346349
digits int
347350
want string
348351
}{
349-
{"0", 10, 'f', 0, "0"},
350-
{"-0", 10, 'f', 0, "-0"},
351-
{"1", 10, 'f', 0, "1"},
352-
{"-1", 10, 'f', 0, "-1"},
353-
354-
{"1.459", 100, 'e', 0, "1e+00"},
355-
{"2.459", 100, 'e', 1, "2.5e+00"},
356-
{"3.459", 100, 'e', 2, "3.46e+00"},
357-
{"4.459", 100, 'e', 3, "4.459e+00"},
358-
{"5.459", 100, 'e', 4, "5.4590e+00"},
359-
360-
{"1.459", 100, 'E', 0, "1E+00"},
361-
{"2.459", 100, 'E', 1, "2.5E+00"},
362-
{"3.459", 100, 'E', 2, "3.46E+00"},
363-
{"4.459", 100, 'E', 3, "4.459E+00"},
364-
{"5.459", 100, 'E', 4, "5.4590E+00"},
365-
366-
{"1.459", 100, 'f', 0, "1"},
367-
{"2.459", 100, 'f', 1, "2.5"},
368-
{"3.459", 100, 'f', 2, "3.46"},
369-
{"4.459", 100, 'f', 3, "4.459"},
370-
{"5.459", 100, 'f', 4, "5.4590"},
371-
372-
{"1.459", 100, 'g', 0, "1"},
373-
{"2.459", 100, 'g', 1, "2"},
374-
{"3.459", 100, 'g', 2, "3.5"},
375-
{"4.459", 100, 'g', 3, "4.46"},
376-
{"5.459", 100, 'g', 4, "5.459"},
377-
378-
{"1459", 53, 'g', 0, "1e+03"},
379-
{"2459", 53, 'g', 1, "2e+03"},
380-
{"3459", 53, 'g', 2, "3.5e+03"},
381-
{"4459", 53, 'g', 3, "4.46e+03"},
382-
{"5459", 53, 'g', 4, "5459"},
383-
384-
{"1459", 53, 'G', 0, "1E+03"},
385-
{"2459", 53, 'G', 1, "2E+03"},
386-
{"3459", 53, 'G', 2, "3.5E+03"},
387-
{"4459", 53, 'G', 3, "4.46E+03"},
388-
{"5459", 53, 'G', 4, "5459"},
389-
390-
{"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
391-
{"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
392-
{"3", 10, 'g', 40, "3"},
393-
394-
{"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
395-
{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
396-
{"3e40", 100, 'g', 40, "3e+40"},
352+
{"0", defaultRound, 10, 'f', 0, "0"},
353+
{"-0", defaultRound, 10, 'f', 0, "-0"},
354+
{"1", defaultRound, 10, 'f', 0, "1"},
355+
{"-1", defaultRound, 10, 'f', 0, "-1"},
356+
357+
{"1.459", defaultRound, 100, 'e', 0, "1e+00"},
358+
{"2.459", defaultRound, 100, 'e', 1, "2.5e+00"},
359+
{"3.459", defaultRound, 100, 'e', 2, "3.46e+00"},
360+
{"4.459", defaultRound, 100, 'e', 3, "4.459e+00"},
361+
{"5.459", defaultRound, 100, 'e', 4, "5.4590e+00"},
362+
363+
{"1.459", defaultRound, 100, 'E', 0, "1E+00"},
364+
{"2.459", defaultRound, 100, 'E', 1, "2.5E+00"},
365+
{"3.459", defaultRound, 100, 'E', 2, "3.46E+00"},
366+
{"4.459", defaultRound, 100, 'E', 3, "4.459E+00"},
367+
{"5.459", defaultRound, 100, 'E', 4, "5.4590E+00"},
368+
369+
{"1.459", defaultRound, 100, 'f', 0, "1"},
370+
{"2.459", defaultRound, 100, 'f', 1, "2.5"},
371+
{"3.459", defaultRound, 100, 'f', 2, "3.46"},
372+
{"4.459", defaultRound, 100, 'f', 3, "4.459"},
373+
{"5.459", defaultRound, 100, 'f', 4, "5.4590"},
374+
375+
{"1.459", defaultRound, 100, 'g', 0, "1"},
376+
{"2.459", defaultRound, 100, 'g', 1, "2"},
377+
{"3.459", defaultRound, 100, 'g', 2, "3.5"},
378+
{"4.459", defaultRound, 100, 'g', 3, "4.46"},
379+
{"5.459", defaultRound, 100, 'g', 4, "5.459"},
380+
381+
{"1459", defaultRound, 53, 'g', 0, "1e+03"},
382+
{"2459", defaultRound, 53, 'g', 1, "2e+03"},
383+
{"3459", defaultRound, 53, 'g', 2, "3.5e+03"},
384+
{"4459", defaultRound, 53, 'g', 3, "4.46e+03"},
385+
{"5459", defaultRound, 53, 'g', 4, "5459"},
386+
387+
{"1459", defaultRound, 53, 'G', 0, "1E+03"},
388+
{"2459", defaultRound, 53, 'G', 1, "2E+03"},
389+
{"3459", defaultRound, 53, 'G', 2, "3.5E+03"},
390+
{"4459", defaultRound, 53, 'G', 3, "4.46E+03"},
391+
{"5459", defaultRound, 53, 'G', 4, "5459"},
392+
393+
{"3", defaultRound, 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
394+
{"3", defaultRound, 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
395+
{"3", defaultRound, 10, 'g', 40, "3"},
396+
397+
{"3e40", defaultRound, 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
398+
{"3e40", defaultRound, 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
399+
{"3e40", defaultRound, 100, 'g', 40, "3e+40"},
397400

398401
// make sure "stupid" exponents don't stall the machine
399-
{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
400-
{"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
401-
{"1e646456993", 64, 'p', 0, "+Inf"},
402-
{"1e1000000000", 64, 'p', 0, "+Inf"},
403-
{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
404-
{"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
405-
{"1e-646456994", 64, 'p', 0, "0"},
406-
{"1e-1000000000", 64, 'p', 0, "0"},
402+
{"1e1000000", defaultRound, 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
403+
{"1e646456992", defaultRound, 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
404+
{"1e646456993", defaultRound, 64, 'p', 0, "+Inf"},
405+
{"1e1000000000", defaultRound, 64, 'p', 0, "+Inf"},
406+
{"1e-1000000", defaultRound, 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
407+
{"1e-646456993", defaultRound, 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
408+
{"1e-646456994", defaultRound, 64, 'p', 0, "0"},
409+
{"1e-1000000000", defaultRound, 64, 'p', 0, "0"},
407410

408411
// minimum and maximum values
409-
{"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"},
410-
{"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"},
411-
{"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"},
412-
{"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"},
412+
{"1p2147483646", defaultRound, 64, 'p', 0, "0x.8p+2147483647"},
413+
{"0x.8p2147483647", defaultRound, 64, 'p', 0, "0x.8p+2147483647"},
414+
{"0x.8p-2147483647", defaultRound, 64, 'p', 0, "0x.8p-2147483647"},
415+
{"1p-2147483649", defaultRound, 64, 'p', 0, "0x.8p-2147483648"},
413416

414417
// TODO(gri) need tests for actual large Floats
415418

416-
{"0", 53, 'b', 0, "0"},
417-
{"-0", 53, 'b', 0, "-0"},
418-
{"1.0", 53, 'b', 0, "4503599627370496p-52"},
419-
{"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
420-
{"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
419+
{"0", defaultRound, 53, 'b', 0, "0"},
420+
{"-0", defaultRound, 53, 'b', 0, "-0"},
421+
{"1.0", defaultRound, 53, 'b', 0, "4503599627370496p-52"},
422+
{"-1.0", defaultRound, 53, 'b', 0, "-4503599627370496p-52"},
423+
{"4503599627370496", defaultRound, 53, 'b', 0, "4503599627370496p+0"},
421424

422425
// issue 9939
423-
{"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
424-
{"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
425-
{"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
426-
{"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
427-
{"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
428-
{"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
429-
430-
{"3", 350, 'p', 0, "0x.cp+2"},
431-
{"03", 350, 'p', 0, "0x.cp+2"},
432-
{"3.", 350, 'p', 0, "0x.cp+2"},
433-
{"3.0", 350, 'p', 0, "0x.cp+2"},
434-
{"3.00", 350, 'p', 0, "0x.cp+2"},
435-
{"3.000", 350, 'p', 0, "0x.cp+2"},
436-
437-
{"0", 64, 'p', 0, "0"},
438-
{"-0", 64, 'p', 0, "-0"},
439-
{"1024.0", 64, 'p', 0, "0x.8p+11"},
440-
{"-1024.0", 64, 'p', 0, "-0x.8p+11"},
441-
442-
// unsupported format
443-
//{"3.14", 64, 'x', 0, "%x"},
444-
//{"-3.14", 64, 'x', 0, "%x"},
426+
{"3", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
427+
{"03", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
428+
{"3.", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
429+
{"3.0", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
430+
{"3.00", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
431+
{"3.000", defaultRound, 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
432+
433+
{"3", defaultRound, 350, 'p', 0, "0x.cp+2"},
434+
{"03", defaultRound, 350, 'p', 0, "0x.cp+2"},
435+
{"3.", defaultRound, 350, 'p', 0, "0x.cp+2"},
436+
{"3.0", defaultRound, 350, 'p', 0, "0x.cp+2"},
437+
{"3.00", defaultRound, 350, 'p', 0, "0x.cp+2"},
438+
{"3.000", defaultRound, 350, 'p', 0, "0x.cp+2"},
439+
440+
{"0", defaultRound, 64, 'p', 0, "0"},
441+
{"-0", defaultRound, 64, 'p', 0, "-0"},
442+
{"1024.0", defaultRound, 64, 'p', 0, "0x.8p+11"},
443+
{"-1024.0", defaultRound, 64, 'p', 0, "-0x.8p+11"},
444+
445+
{"0", defaultRound, 64, 'x', -1, "0x0p+00"},
446+
{"0", defaultRound, 64, 'x', 0, "0x0p+00"},
447+
{"0", defaultRound, 64, 'x', 1, "0x0.0p+00"},
448+
{"0", defaultRound, 64, 'x', 5, "0x0.00000p+00"},
449+
{"3.25", defaultRound, 64, 'x', 0, "0x1p+02"},
450+
{"-3.25", defaultRound, 64, 'x', 0, "-0x1p+02"},
451+
{"3.25", defaultRound, 64, 'x', 1, "0x1.ap+01"},
452+
{"-3.25", defaultRound, 64, 'x', 1, "-0x1.ap+01"},
453+
{"3.25", defaultRound, 64, 'x', -1, "0x1.ap+01"},
454+
{"-3.25", defaultRound, 64, 'x', -1, "-0x1.ap+01"},
455+
{"1024.0", defaultRound, 64, 'x', 0, "0x1p+10"},
456+
{"-1024.0", defaultRound, 64, 'x', 0, "-0x1p+10"},
457+
{"1024.0", defaultRound, 64, 'x', 5, "0x1.00000p+10"},
458+
{"8191.0", defaultRound, 53, 'x', -1, "0x1.fffp+12"},
459+
{"8191.5", defaultRound, 53, 'x', -1, "0x1.fff8p+12"},
460+
{"8191.53125", defaultRound, 53, 'x', -1, "0x1.fff88p+12"},
461+
{"8191.53125", defaultRound, 53, 'x', 4, "0x1.fff8p+12"},
462+
{"8191.53125", defaultRound, 53, 'x', 3, "0x1.000p+13"},
463+
{"8191.53125", defaultRound, 53, 'x', 0, "0x1p+13"},
464+
{"8191.533203125", defaultRound, 53, 'x', -1, "0x1.fff888p+12"},
465+
{"8191.533203125", defaultRound, 53, 'x', 5, "0x1.fff88p+12"},
466+
{"8191.533203125", defaultRound, 53, 'x', 4, "0x1.fff9p+12"},
467+
468+
{"8191.53125", defaultRound, 53, 'x', -1, "0x1.fff88p+12"},
469+
{"8191.53125", ToNearestEven, 53, 'x', 5, "0x1.fff88p+12"},
470+
{"8191.53125", ToNearestAway, 53, 'x', 5, "0x1.fff88p+12"},
471+
{"8191.53125", ToZero, 53, 'x', 5, "0x1.fff88p+12"},
472+
{"8191.53125", AwayFromZero, 53, 'x', 5, "0x1.fff88p+12"},
473+
{"8191.53125", ToNegativeInf, 53, 'x', 5, "0x1.fff88p+12"},
474+
{"8191.53125", ToPositiveInf, 53, 'x', 5, "0x1.fff88p+12"},
475+
476+
{"8191.53125", defaultRound, 53, 'x', 4, "0x1.fff8p+12"},
477+
{"8191.53125", defaultRound, 53, 'x', 3, "0x1.000p+13"},
478+
{"8191.53125", defaultRound, 53, 'x', 0, "0x1p+13"},
479+
{"8191.533203125", defaultRound, 53, 'x', -1, "0x1.fff888p+12"},
480+
{"8191.533203125", defaultRound, 53, 'x', 6, "0x1.fff888p+12"},
481+
{"8191.533203125", defaultRound, 53, 'x', 5, "0x1.fff88p+12"},
482+
{"8191.533203125", defaultRound, 53, 'x', 4, "0x1.fff9p+12"},
483+
484+
{"8191.53125", ToNearestEven, 53, 'x', 4, "0x1.fff8p+12"},
485+
{"8191.53125", ToNearestAway, 53, 'x', 4, "0x1.fff9p+12"},
486+
{"8191.53125", ToZero, 53, 'x', 4, "0x1.fff8p+12"},
487+
{"8191.53125", ToZero, 53, 'x', 2, "0x1.ffp+12"},
488+
{"8191.53125", AwayFromZero, 53, 'x', 4, "0x1.fff9p+12"},
489+
{"8191.53125", ToNegativeInf, 53, 'x', 4, "0x1.fff8p+12"},
490+
{"-8191.53125", ToNegativeInf, 53, 'x', 4, "-0x1.fff9p+12"},
491+
{"8191.53125", ToPositiveInf, 53, 'x', 4, "0x1.fff9p+12"},
492+
{"-8191.53125", ToPositiveInf, 53, 'x', 4, "-0x1.fff8p+12"},
445493
} {
446494
f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
447495
if err != nil {
448496
t.Errorf("%v: %s", test, err)
449497
continue
450498
}
499+
if test.round != defaultRound {
500+
f.SetMode(test.round)
501+
}
451502

452503
got := f.Text(test.format, test.digits)
453504
if got != test.want {
@@ -458,7 +509,7 @@ func TestFloatText(t *testing.T) {
458509
// ('p' format is not supported by strconv.FormatFloat,
459510
// and its output for 0.0 prints a biased exponent value
460511
// as in 0p-1074 which makes no sense to emulate here)
461-
if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
512+
if test.prec == 53 && test.format != 'p' && f.Sign() != 0 && (test.round == ToNearestEven || test.round == defaultRound) {
462513
f64, acc := f.Float64()
463514
if acc != Exact {
464515
t.Errorf("%v: expected exact conversion to float64", test)

0 commit comments

Comments
 (0)