1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 var exponentTests = []struct {
19 s string // string to be scanned
20 base2ok bool // true if 'p'/'P' exponents are accepted
21 sepOk bool // true if '_' separators are accepted
22 x int64 // expected exponent
23 b int // expected exponent base
24 err error // expected error
25 next rune // next character (or 0, if at EOF)
27 // valid, without separators
28 {"", false, false, 0, 10, nil, 0},
29 {"1", false, false, 0, 10, nil, '1'},
30 {"e0", false, false, 0, 10, nil, 0},
31 {"E1", false, false, 1, 10, nil, 0},
32 {"e+10", false, false, 10, 10, nil, 0},
33 {"e-10", false, false, -10, 10, nil, 0},
34 {"e123456789a", false, false, 123456789, 10, nil, 'a'},
35 {"p", false, false, 0, 10, nil, 'p'},
36 {"P+100", false, false, 0, 10, nil, 'P'},
37 {"p0", true, false, 0, 2, nil, 0},
38 {"P-123", true, false, -123, 2, nil, 0},
39 {"p+0a", true, false, 0, 2, nil, 'a'},
40 {"p+123__", true, false, 123, 2, nil, '_'}, // '_' is not part of the number anymore
42 // valid, with separators
43 {"e+1_0", false, true, 10, 10, nil, 0},
44 {"e-1_0", false, true, -10, 10, nil, 0},
45 {"e123_456_789a", false, true, 123456789, 10, nil, 'a'},
46 {"P+1_00", false, true, 0, 10, nil, 'P'},
47 {"p-1_2_3", true, true, -123, 2, nil, 0},
50 {"e", false, false, 0, 10, errNoDigits, 0},
51 {"ef", false, false, 0, 10, errNoDigits, 'f'},
52 {"e+", false, false, 0, 10, errNoDigits, 0},
53 {"E-x", false, false, 0, 10, errNoDigits, 'x'},
54 {"p", true, false, 0, 2, errNoDigits, 0},
55 {"P-", true, false, 0, 2, errNoDigits, 0},
56 {"p+e", true, false, 0, 2, errNoDigits, 'e'},
57 {"e+_x", false, true, 0, 10, errNoDigits, 'x'},
59 // invalid: incorrect use of separator
60 {"e0_", false, true, 0, 10, errInvalSep, 0},
61 {"e_0", false, true, 0, 10, errInvalSep, 0},
62 {"e-1_2__3", false, true, -123, 10, errInvalSep, 0},
65 func TestScanExponent(t *testing.T) {
66 for _, a := range exponentTests {
67 r := strings.NewReader(a.s)
68 x, b, err := scanExponent(r, a.base2ok, a.sepOk)
70 t.Errorf("scanExponent%+v\n\tgot error = %v; want %v", a, err, a.err)
73 t.Errorf("scanExponent%+v\n\tgot z = %v; want %v", a, x, a.x)
76 t.Errorf("scanExponent%+v\n\tgot b = %d; want %d", a, b, a.b)
78 next, _, err := r.ReadRune()
83 if err == nil && next != a.next {
84 t.Errorf("scanExponent%+v\n\tgot next = %q; want %q", a, next, a.next)
89 type StringTest struct {
94 var setStringTests = []StringTest{
104 {in: "4/3/2"}, // issue 17001
108 {in: "13e-9223372036854775808"}, // CVE-2022-23772
117 {"1.e1", "10", true},
118 {"-0.1", "-1/10", true},
119 {"-.1", "-1/10", true},
120 {"2/4", "1/2", true},
121 {".25", "1/4", true},
122 {"-1/5", "-1/5", true},
123 {"8129567.7690E14", "812956776900000000000", true},
124 {"78189e+4", "781890000", true},
125 {"553019.8935e+8", "55301989350000", true},
126 {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
127 {"9877861857500000E-7", "3951144743/4", true},
128 {"2169378.417e-3", "2169378417/1000000", true},
129 {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
130 {"53/70893980658822810696", "53/70893980658822810696", true},
131 {"106/141787961317645621392", "53/70893980658822810696", true},
132 {"204211327800791583.81095", "4084226556015831676219/20000", true},
133 {"0e9999999999", "0", true}, // issue #16176
136 // These are not supported by fmt.Fscanf.
137 var setStringTests2 = []StringTest{
143 // invalid with separators
144 // (smoke tests only - a comprehensive set of tests is in natconv_test.go)
150 {"0b1000/3", "8/3", true},
151 {"0B1000/0x8", "1", true},
152 {"-010/1", "-8", true}, // 0-prefix indicates octal in this case
153 {"-010.0", "-10", true},
154 {"-0o10/1", "-8", true},
155 {"0x10/1", "16", true},
156 {"0x10/0x20", "1/2", true},
158 {"0010", "10", true}, // 0-prefix is ignored in this case (not a fraction)
159 {"0x10.0", "16", true},
160 {"0x1.8", "3/2", true},
161 {"0X1.8p4", "24", true},
162 {"0x1.1E2", "2289/2048", true}, // E is part of hex mantissa, not exponent
163 {"0b1.1E2", "150", true},
164 {"0B1.1P3", "12", true},
165 {"0o10e-2", "2/25", true},
166 {"0O10p-3", "1", true},
168 // valid with separators
169 // (smoke tests only - a comprehensive set of tests is in natconv_test.go)
170 {"0b_1000/3", "8/3", true},
171 {"0B_10_00/0x8", "1", true},
172 {"0xdead/0B1101_1110_1010_1101", "1", true},
173 {"0B1101_1110_1010_1101/0XD_E_A_D", "1", true},
174 {"1_000.0", "1000", true},
176 {"0x_10.0", "16", true},
177 {"0x1_0.0", "16", true},
178 {"0x1.8_0", "3/2", true},
179 {"0X1.8p0_4", "24", true},
180 {"0b1.1_0E2", "150", true},
181 {"0o1_0e-2", "2/25", true},
182 {"0O_10p-3", "1", true},
185 func TestRatSetString(t *testing.T) {
186 var tests []StringTest
187 tests = append(tests, setStringTests...)
188 tests = append(tests, setStringTests2...)
190 for i, test := range tests {
191 x, ok := new(Rat).SetString(test.in)
195 t.Errorf("#%d SetString(%q) expected failure", i, test.in)
196 } else if x.RatString() != test.out {
197 t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
201 t.Errorf("#%d SetString(%q) expected success", i, test.in)
203 t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
209 func TestRatSetStringZero(t *testing.T) {
210 got, _ := new(Rat).SetString("0")
211 want := new(Rat).SetInt64(0)
212 if !reflect.DeepEqual(got, want) {
213 t.Errorf("got %#+v, want %#+v", got, want)
217 func TestRatScan(t *testing.T) {
219 for i, test := range setStringTests {
222 buf.WriteString(test.in)
224 _, err := fmt.Fscanf(&buf, "%v", x)
225 if err == nil != test.ok {
227 t.Errorf("#%d (%s) error: %s", i, test.in, err)
229 t.Errorf("#%d (%s) expected error", i, test.in)
233 if err == nil && x.RatString() != test.out {
234 t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
239 var floatStringTests = []struct {
250 {"-0.05", 1, "-0.1"},
254 {"-1/3", 3, "-0.333"},
255 {"-2/3", 4, "-0.6667"},
257 {"0.999", 2, "1.00"},
263 func TestFloatString(t *testing.T) {
264 for i, test := range floatStringTests {
265 x, _ := new(Rat).SetString(test.in)
267 if x.FloatString(test.prec) != test.out {
268 t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
273 // Test inputs to Rat.SetString. The prefix "long:" causes the test
274 // to be skipped except in -long mode. (The threshold is about 500us.)
275 var float64inputs = []string{
276 // Constants plundered from strconv/testfp.txt.
278 // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
291 "3142213164987e-294",
292 "46202199371337e-072",
293 "231010996856685e-073",
294 "9324754620109615e+212",
295 "78459735791271921e+049",
296 "272104041512242479e+200",
297 "6802601037806061975e+198",
298 "20505426358836677347e-221",
299 "836168422905420598437e-234",
300 "4891559871276714924261e+222",
302 // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
315 "2335141086879e+218",
316 "36167929443327e-159",
317 "609610927149051e-255",
318 "3743626360493413e-165",
319 "94080055902682397e-242",
320 "899810892172646163e+283",
321 "7120190517612959703e+120",
322 "25188282901709339043e-252",
323 "308984926168550152811e-052",
324 "6372891218502368041059e+064",
326 // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
340 // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
354 // Constants plundered from strconv/atof_test.go.
361 "100000000000000000000000",
364 "99999999999999974834176",
365 "100000000000000000000001",
366 "100000000000000008388608",
367 "100000000000000016777215",
368 "100000000000000016777216",
371 "-0", // NB: exception made for this input
376 "1.7976931348623157e308",
377 "-1.7976931348623157e308",
378 // next float64 - too large
379 "1.7976931348623159e308",
380 "-1.7976931348623159e308",
381 // the border is ...158079
383 "1.7976931348623158e308",
384 "-1.7976931348623158e308",
385 // borderline - too large
386 "1.797693134862315808e308",
387 "-1.797693134862315808e308",
389 // a little too large
419 // way too small, negative
423 // try to overflow exponent
424 // [Disabled: too slow and memory-hungry with rationals.]
427 // "1e-18446744073709551616",
428 // "1e+18446744073709551616",
430 // https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
431 "2.2250738585072012e-308",
432 // https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
433 "2.2250738585072011e-308",
435 // A very large number (initially wrongly parsed by the fast algorithm).
436 "4.630813248087435e+307",
438 // A different kind of very large number.
439 "22.222222222222222",
440 "long:2." + strings.Repeat("2", 4000) + "e+1",
442 // Exactly halfway between 1 and math.Nextafter(1, 2).
443 // Round to even (down).
444 "1.00000000000000011102230246251565404236316680908203125",
445 // Slightly lower; still round down.
446 "1.00000000000000011102230246251565404236316680908203124",
447 // Slightly higher; round up.
448 "1.00000000000000011102230246251565404236316680908203126",
449 // Slightly higher, but you have to read all the way to the end.
450 "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
452 // Smallest denormal, 2^(-1022-52)
453 "4.940656458412465441765687928682213723651e-324",
454 // Half of smallest denormal, 2^(-1022-53)
455 "2.470328229206232720882843964341106861825e-324",
456 // A little more than the exact half of smallest denormal
457 // 2^-1075 + 2^-1100. (Rounds to 1p-1074.)
458 "2.470328302827751011111470718709768633275e-324",
459 // The exact halfway between smallest normal and largest denormal:
460 // 2^-1022 - 2^-1075. (Rounds to 2^-1022.)
461 "2.225073858507201136057409796709131975935e-308",
463 "1152921504606846975", // 1<<60 - 1
464 "-1152921504606846975", // -(1<<60 - 1)
465 "1152921504606846977", // 1<<60 + 1
466 "-1152921504606846977", // -(1<<60 + 1)
471 // isFinite reports whether f represents a finite rational value.
472 // It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
473 func isFinite(f float64) bool {
474 return math.Abs(f) <= math.MaxFloat64
477 func TestFloat32SpecialCases(t *testing.T) {
478 for _, input := range float64inputs {
479 if strings.HasPrefix(input, "long:") {
483 input = input[len("long:"):]
486 r, ok := new(Rat).SetString(input)
488 t.Errorf("Rat.SetString(%q) failed", input)
491 f, exact := r.Float32()
493 // 1. Check string -> Rat -> float32 conversions are
494 // consistent with strconv.ParseFloat.
495 // Skip this check if the input uses "a/b" rational syntax.
496 if !strings.Contains(input, "/") {
497 e64, _ := strconv.ParseFloat(input, 32)
500 // Careful: negative Rats too small for
501 // float64 become -0, but Rat obviously cannot
502 // preserve the sign from SetString("-0").
504 case math.Float32bits(e) == math.Float32bits(f):
505 // Ok: bitwise equal.
506 case f == 0 && r.Num().BitLen() == 0:
507 // Ok: Rat(0) is equivalent to both +/- float64(0).
509 t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
513 if !isFinite(float64(f)) {
517 // 2. Check f is best approximation to r.
518 if !checkIsBestApprox32(t, f, r) {
519 // Append context information.
520 t.Errorf("(input was %q)", input)
523 // 3. Check f->R->f roundtrip is non-lossy.
524 checkNonLossyRoundtrip32(t, f)
526 // 4. Check exactness using slow algorithm.
527 if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
528 t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
533 func TestFloat64SpecialCases(t *testing.T) {
534 for _, input := range float64inputs {
535 if strings.HasPrefix(input, "long:") {
539 input = input[len("long:"):]
542 r, ok := new(Rat).SetString(input)
544 t.Errorf("Rat.SetString(%q) failed", input)
547 f, exact := r.Float64()
549 // 1. Check string -> Rat -> float64 conversions are
550 // consistent with strconv.ParseFloat.
551 // Skip this check if the input uses "a/b" rational syntax.
552 if !strings.Contains(input, "/") {
553 e, _ := strconv.ParseFloat(input, 64)
555 // Careful: negative Rats too small for
556 // float64 become -0, but Rat obviously cannot
557 // preserve the sign from SetString("-0").
559 case math.Float64bits(e) == math.Float64bits(f):
560 // Ok: bitwise equal.
561 case f == 0 && r.Num().BitLen() == 0:
562 // Ok: Rat(0) is equivalent to both +/- float64(0).
564 t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
572 // 2. Check f is best approximation to r.
573 if !checkIsBestApprox64(t, f, r) {
574 // Append context information.
575 t.Errorf("(input was %q)", input)
578 // 3. Check f->R->f roundtrip is non-lossy.
579 checkNonLossyRoundtrip64(t, f)
581 // 4. Check exactness using slow algorithm.
582 if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
583 t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
588 func TestIssue31184(t *testing.T) {
590 for _, want := range []string{
596 got := x.FloatString(3)
598 t.Errorf("got %s, want %s", got, want)
603 func TestIssue45910(t *testing.T) {
605 for _, test := range []struct {
609 {"1e-1000001", false},
610 {"1e-1000000", true},
611 {"1e+1000000", true},
612 {"1e+1000001", false},
614 {"0p1000000000000", true},
615 {"1p-10000001", false},
616 {"1p-10000000", true},
617 {"1p+10000000", true},
618 {"1p+10000001", false},
619 {"1.770p02041010010011001001", false}, // test case from issue
621 _, got := x.SetString(test.input)
622 if got != test.want {
623 t.Errorf("SetString(%s) got ok = %v; want %v", test.input, got, test.want)
627 func TestFloatPrec(t *testing.T) {
628 var tests = []struct {
634 // examples from the issue #50489
635 {"10/100", 1, true, "0.1"},
636 {"3/100", 2, true, "0.03"},
637 {"10", 0, true, "10"},
640 {"zero", 0, true, "0"}, // test uninitialized zero value for Rat
641 {"0", 0, true, "0"}, // 0
642 {"1", 0, true, "1"}, // 1
643 {"1/2", 1, true, "0.5"}, // 0.5
644 {"1/3", 0, false, "0"}, // 0.(3)
645 {"1/4", 2, true, "0.25"}, // 0.25
646 {"1/5", 1, true, "0.2"}, // 0.2
647 {"1/6", 1, false, "0.2"}, // 0.1(6)
648 {"1/7", 0, false, "0"}, // 0.(142857)
649 {"1/8", 3, true, "0.125"}, // 0.125
650 {"1/9", 0, false, "0"}, // 0.(1)
651 {"1/10", 1, true, "0.1"}, // 0.1
652 {"1/11", 0, false, "0"}, // 0.(09)
653 {"1/12", 2, false, "0.08"}, // 0.08(3)
654 {"1/13", 0, false, "0"}, // 0.(076923)
655 {"1/14", 1, false, "0.1"}, // 0.0(714285)
656 {"1/15", 1, false, "0.1"}, // 0.0(6)
657 {"1/16", 4, true, "0.0625"}, // 0.0625
659 {"10/2", 0, true, "5"}, // 5
660 {"10/3", 0, false, "3"}, // 3.(3)
661 {"10/6", 0, false, "2"}, // 1.(6)
662 {"1/10000000", 7, true, "0.0000001"}, // 0.0000001
663 {"1/3125", 5, true, "0.00032"}, // "0.00032"
664 {"1/1024", 10, true, "0.0009765625"}, // 0.0009765625
665 {"1/304000", 7, false, "0.0000033"}, // 0.0000032(894736842105263157)
666 {"1/48828125", 11, true, "0.00000002048"}, // 0.00000002048
669 for _, test := range tests {
672 // check uninitialized zero value
673 if test.f != "zero" {
674 _, ok := f.SetString(test.f)
676 t.Fatalf("invalid test case: f = %s", test.f)
680 // results for f and -f must be the same
682 for i := 0; i < 2; i++ {
683 prec, ok := f.FloatPrec()
684 if prec != test.prec || ok != test.ok {
685 t.Errorf("%s: FloatPrec(%s): got prec, ok = %d, %v; want %d, %v", test.f, &f, prec, ok, test.prec, test.ok)
687 s := f.FloatString(test.prec)
689 t.Errorf("%s: FloatString(%s, %d): got %s; want %s", test.f, &f, prec, s, fdec)
691 // proceed with -f but don't add a "-" before a "0"
700 func BenchmarkFloatPrecExact(b *testing.B) {
701 for _, n := range []int{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6} {
704 p := NewInt(int64(n))
709 r.SetFrac(NewInt(1), d)
711 b.Run(fmt.Sprint(n), func(b *testing.B) {
712 for i := 0; i < b.N; i++ {
713 prec, ok := r.FloatPrec()
714 if prec != n || !ok {
715 b.Fatalf("got exact, ok = %d, %v; want %d, %v", prec, ok, uint64(n), true)
722 func BenchmarkFloatPrecInexact(b *testing.B) {
723 for _, n := range []int{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6} {
726 p := NewInt(int64(n))
732 r.SetFrac(NewInt(1), d)
734 b.Run(fmt.Sprint(n), func(b *testing.B) {
735 for i := 0; i < b.N; i++ {
736 _, ok := r.FloatPrec()
738 b.Fatalf("got unexpected ok")