diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-02 16:38:43 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-02 16:38:43 +0000 |
commit | cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce (patch) | |
tree | efa0c55763b34cbc633bc494c2743d1b5d9aaff3 /libgo/go/strconv | |
parent | ff2f581b00ac6759f6366c16ef902c935163aa13 (diff) | |
download | gcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.zip gcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.tar.gz gcc-cbb6491d76c7aa81cdf5d3b3a81386129c5e2fce.tar.bz2 |
libgo: Update to weekly.2012-02-14 release.
From-SVN: r184798
Diffstat (limited to 'libgo/go/strconv')
-rw-r--r-- | libgo/go/strconv/atof.go | 10 | ||||
-rw-r--r-- | libgo/go/strconv/atof_test.go | 53 | ||||
-rw-r--r-- | libgo/go/strconv/decimal.go | 41 |
3 files changed, 88 insertions, 16 deletions
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go index 42fc431..cd3031b 100644 --- a/libgo/go/strconv/atof.go +++ b/libgo/go/strconv/atof.go @@ -52,10 +52,10 @@ func special(s string) (f float64, ok bool) { return } -// TODO(rsc): Better truncation handling. func (b *decimal) set(s string) (ok bool) { i := 0 b.neg = false + b.trunc = false // optional sign if i >= len(s) { @@ -88,8 +88,12 @@ func (b *decimal) set(s string) (ok bool) { b.dp-- continue } - b.d[b.nd] = s[i] - b.nd++ + if b.nd < len(b.d) { + b.d[b.nd] = s[i] + b.nd++ + } else if s[i] != '0' { + b.trunc = true + } continue } break diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go index 3fa637d..5995023 100644 --- a/libgo/go/strconv/atof_test.go +++ b/libgo/go/strconv/atof_test.go @@ -9,6 +9,7 @@ import ( "math/rand" "reflect" . "strconv" + "strings" "testing" "time" ) @@ -117,6 +118,20 @@ var atoftests = []atofTest{ // A very large number (initially wrongly parsed by the fast algorithm). {"4.630813248087435e+307", "4.630813248087435e+307", nil}, + + // A different kind of very large number. + {"22.222222222222222", "22.22222222222222", nil}, + {"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil}, + + // Exactly halfway between 1 and math.Nextafter(1, 2). + // Round to even (down). + {"1.00000000000000011102230246251565404236316680908203125", "1", nil}, + // Slightly lower; still round down. + {"1.00000000000000011102230246251565404236316680908203124", "1", nil}, + // Slightly higher; round up. + {"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil}, + // Slightly higher, but you have to read all the way to the end. + {"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil}, } type atofSimpleTest struct { @@ -211,6 +226,44 @@ func TestAtofRandom(t *testing.T) { t.Logf("tested %d random numbers", len(atofRandomTests)) } +var roundTripCases = []struct { + f float64 + s string +}{ + // Issue 2917. + // This test will break the optimized conversion if the + // FPU is using 80-bit registers instead of 64-bit registers, + // usually because the operating system initialized the + // thread with 80-bit precision and the Go runtime didn't + // fix the FP control word. + {8865794286000691 << 39, "4.87402195346389e+27"}, + {8865794286000692 << 39, "4.8740219534638903e+27"}, +} + +func TestRoundTrip(t *testing.T) { + for _, tt := range roundTripCases { + old := SetOptimize(false) + s := FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("no-opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err := ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("no-opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(true) + s = FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err = ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(old) + } +} + func BenchmarkAtof64Decimal(b *testing.B) { for i := 0; i < b.N; i++ { ParseFloat("33909", 64) diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go index cc5591a..a75071d 100644 --- a/libgo/go/strconv/decimal.go +++ b/libgo/go/strconv/decimal.go @@ -12,12 +12,11 @@ package strconv type decimal struct { - // TODO(rsc): Can make d[] a bit smaller and add - // truncated bool; - d [800]byte // digits - nd int // number of digits used - dp int // decimal point - neg bool + d [800]byte // digits + nd int // number of digits used + dp int // decimal point + neg bool + trunc bool // discarded nonzero digits beyond d[:nd] } func (a *decimal) String() string { @@ -145,8 +144,12 @@ func rightShift(a *decimal, k uint) { for n > 0 { dig := n >> k n -= dig << k - a.d[w] = byte(dig + '0') - w++ + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } n = n * 10 } @@ -242,7 +245,11 @@ func leftShift(a *decimal, k uint) { quo := n / 10 rem := n - 10*quo w-- - a.d[w] = byte(rem + '0') + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } n = quo } @@ -251,11 +258,18 @@ func leftShift(a *decimal, k uint) { quo := n / 10 rem := n - 10*quo w-- - a.d[w] = byte(rem + '0') + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } n = quo } a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } a.dp += delta trim(a) } @@ -286,6 +300,10 @@ func shouldRoundUp(a *decimal, nd int) bool { return false } if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + return true + } return nd > 0 && (a.d[nd-1]-'0')%2 != 0 } // not halfway - digit tells all @@ -293,7 +311,6 @@ func shouldRoundUp(a *decimal, nd int) bool { } // Round a to nd digits (or fewer). -// Returns receiver for convenience. // If nd is zero, it means we're rounding // just to the left of the digits, as in // 0.09 -> 0.1. @@ -309,7 +326,6 @@ func (a *decimal) Round(nd int) { } // Round a down to nd digits (or fewer). -// Returns receiver for convenience. func (a *decimal) RoundDown(nd int) { if nd < 0 || nd >= a.nd { return @@ -319,7 +335,6 @@ func (a *decimal) RoundDown(nd int) { } // Round a up to nd digits (or fewer). -// Returns receiver for convenience. func (a *decimal) RoundUp(nd int) { if nd < 0 || nd >= a.nd { return |