diff --git a/src/internal/strconv/atof.go b/src/internal/strconv/atof.go index 443c222279fcea..d1470f05c09eb2 100644 --- a/src/internal/strconv/atof.go +++ b/src/internal/strconv/atof.go @@ -97,6 +97,7 @@ func (b *decimal) set(s string) (ok bool) { // digits sawdot := false sawdigits := false + nd := 0 // number of significant digits for ; i < len(s); i++ { switch { case s[i] == '_': @@ -107,15 +108,16 @@ func (b *decimal) set(s string) (ok bool) { return } sawdot = true - b.dp = b.nd + b.dp = nd continue case '0' <= s[i] && s[i] <= '9': sawdigits = true - if s[i] == '0' && b.nd == 0 { // ignore leading zeros + if s[i] == '0' && nd == 0 { // ignore leading zeros b.dp-- continue } + nd++ if b.nd < len(b.d) { b.d[b.nd] = s[i] b.nd++ @@ -130,7 +132,7 @@ func (b *decimal) set(s string) (ok bool) { return } if !sawdot { - b.dp = b.nd + b.dp = nd } // optional exponent moves decimal point. diff --git a/src/internal/strconv/atof_test.go b/src/internal/strconv/atof_test.go index 3c5135a5db67dd..80d86e5f5da7d2 100644 --- a/src/internal/strconv/atof_test.go +++ b/src/internal/strconv/atof_test.go @@ -300,6 +300,15 @@ var atoftests = []atofTest{ {"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil}, {"0x1.00000000000008" + strings.Repeat("0", 10000) + "1p0", "1.0000000000000002", nil}, + // Integer part longer than the slow path's 800-digit decimal buffer. + {"1" + strings.Repeat("0", 799) + "e-673", "1e+126", nil}, + {"1" + strings.Repeat("0", 800) + "e-674", "1e+126", nil}, + {"1" + strings.Repeat("0", 826) + "e-700", "1e+126", nil}, + {"1" + strings.Repeat("0", 826) + ".5e-700", "1e+126", nil}, + // The nonzero tail sets trunc, and d and d+1 round differently near 1e126, + // so the optimized path falls back to the slow path too. + {"1" + strings.Repeat("0", 824) + "1e-699", "1e+126", nil}, + // Halfway between x := math.Nextafter(1, 2) and math.Nextafter(x, 2) // Round to even (up). {"1.00000000000000033306690738754696212708950042724609375", "1.0000000000000004", nil}, @@ -371,6 +380,9 @@ var atof32tests = []atofTest{ {"1.000000059604644775390625" + strings.Repeat("0", 10000) + "1", "1.0000001", nil}, {"0x1.000001" + strings.Repeat("0", 10000) + "1p0", "1.0000001", nil}, + // Integer part longer than the slow path's 800-digit decimal buffer. + {"1" + strings.Repeat("0", 824) + "1e-795", "1e+30", nil}, + // largest float32: (1<<128) * (1 - 2^-24) {"340282346638528859811704183484516925440", "3.4028235e+38", nil}, {"-340282346638528859811704183484516925440", "-3.4028235e+38", nil},