diff options
Diffstat (limited to 'libgo/go/strconv')
-rw-r--r-- | libgo/go/strconv/atob.go | 28 | ||||
-rw-r--r-- | libgo/go/strconv/atob_test.go | 56 | ||||
-rw-r--r-- | libgo/go/strconv/atof.go | 413 | ||||
-rw-r--r-- | libgo/go/strconv/atof_test.go | 183 | ||||
-rw-r--r-- | libgo/go/strconv/atoi.go | 202 | ||||
-rw-r--r-- | libgo/go/strconv/atoi_test.go | 303 | ||||
-rw-r--r-- | libgo/go/strconv/decimal.go | 371 | ||||
-rw-r--r-- | libgo/go/strconv/decimal_test.go | 117 | ||||
-rw-r--r-- | libgo/go/strconv/fp_test.go | 149 | ||||
-rw-r--r-- | libgo/go/strconv/ftoa.go | 405 | ||||
-rw-r--r-- | libgo/go/strconv/ftoa_test.go | 145 | ||||
-rw-r--r-- | libgo/go/strconv/internal_test.go | 15 | ||||
-rw-r--r-- | libgo/go/strconv/itoa.go | 57 | ||||
-rw-r--r-- | libgo/go/strconv/itoa_test.go | 174 | ||||
-rw-r--r-- | libgo/go/strconv/quote.go | 264 | ||||
-rw-r--r-- | libgo/go/strconv/quote_test.go | 170 | ||||
-rw-r--r-- | libgo/go/strconv/testfp.txt | 181 |
17 files changed, 3233 insertions, 0 deletions
diff --git a/libgo/go/strconv/atob.go b/libgo/go/strconv/atob.go new file mode 100644 index 000000000..69fa2292a --- /dev/null +++ b/libgo/go/strconv/atob.go @@ -0,0 +1,28 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import "os" + +// Atob returns the boolean value represented by the string. +// It accepts 1, t, T, TRUE, true, 0, f, F, FALSE, false. Any other value returns +// an error. +func Atob(str string) (value bool, err os.Error) { + switch str { + case "1", "t", "T", "true", "TRUE", "True": + return true, nil + case "0", "f", "F", "false", "FALSE", "False": + return false, nil + } + return false, &NumError{str, os.EINVAL} +} + +// Btoa returns "true" or "false" according to the value of the boolean argument +func Btoa(b bool) string { + if b { + return "true" + } + return "false" +} diff --git a/libgo/go/strconv/atob_test.go b/libgo/go/strconv/atob_test.go new file mode 100644 index 000000000..497df5b18 --- /dev/null +++ b/libgo/go/strconv/atob_test.go @@ -0,0 +1,56 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "os" + . "strconv" + "testing" +) + +type atobTest struct { + in string + out bool + err os.Error +} + +var atobtests = []atobTest{ + {"", false, os.EINVAL}, + {"asdf", false, os.EINVAL}, + {"0", false, nil}, + {"f", false, nil}, + {"F", false, nil}, + {"FALSE", false, nil}, + {"false", false, nil}, + {"1", true, nil}, + {"t", true, nil}, + {"T", true, nil}, + {"TRUE", true, nil}, + {"true", true, nil}, +} + +func TestAtob(t *testing.T) { + for _, test := range atobtests { + b, e := Atob(test.in) + if test.err != nil { + // expect an error + if e == nil { + t.Errorf("%s: expected %s but got nil", test.in, test.err) + } else { + // NumError assertion must succeed; it's the only thing we return. + if test.err != e.(*NumError).Error { + t.Errorf("%s: expected %s but got %s", test.in, test.err, e) + } + } + } else { + if e != nil { + t.Errorf("%s: expected no error but got %s", test.in, e) + } + if b != test.out { + t.Errorf("%s: expected %t but got %t", test.in, test.out, b) + } + } + } +} diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go new file mode 100644 index 000000000..72f162c51 --- /dev/null +++ b/libgo/go/strconv/atof.go @@ -0,0 +1,413 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// decimal to binary floating point conversion. +// Algorithm: +// 1) Store input in multiprecision decimal. +// 2) Multiply/divide decimal by powers of two until in range [0.5, 1) +// 3) Multiply by 2^precision and round to get mantissa. + +// The strconv package implements conversions to and from +// string representations of basic data types. +package strconv + +import ( + "math" + "os" +) + +var optimize = true // can change for testing + +func equalIgnoreCase(s1, s2 string) bool { + if len(s1) != len(s2) { + return false + } + for i := 0; i < len(s1); i++ { + c1 := s1[i] + if 'A' <= c1 && c1 <= 'Z' { + c1 += 'a' - 'A' + } + c2 := s2[i] + if 'A' <= c2 && c2 <= 'Z' { + c2 += 'a' - 'A' + } + if c1 != c2 { + return false + } + } + return true +} + +func special(s string) (f float64, ok bool) { + switch { + case equalIgnoreCase(s, "nan"): + return math.NaN(), true + case equalIgnoreCase(s, "-inf"): + return math.Inf(-1), true + case equalIgnoreCase(s, "+inf"): + return math.Inf(1), true + case equalIgnoreCase(s, "inf"): + return math.Inf(1), true + } + return +} + +// TODO(rsc): Better truncation handling. +func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) { + i := 0 + + // optional sign + if i >= len(s) { + return + } + switch { + case s[i] == '+': + i++ + case s[i] == '-': + neg = true + i++ + } + + // digits + b := new(decimal) + sawdot := false + sawdigits := false + for ; i < len(s); i++ { + switch { + case s[i] == '.': + if sawdot { + return + } + sawdot = true + b.dp = b.nd + continue + + case '0' <= s[i] && s[i] <= '9': + sawdigits = true + if s[i] == '0' && b.nd == 0 { // ignore leading zeros + b.dp-- + continue + } + b.d[b.nd] = s[i] + b.nd++ + continue + } + break + } + if !sawdigits { + return + } + if !sawdot { + b.dp = b.nd + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && (s[i] == 'e' || s[i] == 'E') { + i++ + if i >= len(s) { + return + } + esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return + } + e := 0 + for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + if e < 10000 { + e = e*10 + int(s[i]) - '0' + } + } + b.dp += e * esign + } + + if i != len(s) { + return + } + + d = b + ok = true + return +} + +// decimal power of ten to binary power of two. +var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26} + +func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uint64, overflow bool) { + var exp int + var mant uint64 + + // Zero is always a special case. + if d.nd == 0 { + mant = 0 + exp = flt.bias + goto out + } + + // Obvious overflow/underflow. + // These bounds are for 64-bit floats. + // Will have to change if we want to support 80-bit floats in the future. + if d.dp > 310 { + goto overflow + } + if d.dp < -330 { + // zero + mant = 0 + exp = flt.bias + goto out + } + + // Scale by powers of two until in range [0.5, 1.0) + exp = 0 + for d.dp > 0 { + var n int + if d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[d.dp] + } + d.Shift(-n) + exp += n + } + for d.dp < 0 || d.dp == 0 && d.d[0] < '5' { + var n int + if -d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[-d.dp] + } + d.Shift(n) + exp -= n + } + + // Our range is [0.5,1) but floating point range is [1,2). + exp-- + + // Minimum representable exponent is flt.bias+1. + // If the exponent is smaller, move it up and + // adjust d accordingly. + if exp < flt.bias+1 { + n := flt.bias + 1 - exp + d.Shift(-n) + exp += n + } + + if exp-flt.bias >= 1<<flt.expbits-1 { + goto overflow + } + + // Extract 1+flt.mantbits bits. + mant = d.Shift(int(1 + flt.mantbits)).RoundedInteger() + + // Rounding might have added a bit; shift down. + if mant == 2<<flt.mantbits { + mant >>= 1 + exp++ + if exp-flt.bias >= 1<<flt.expbits-1 { + goto overflow + } + } + + // Denormalized? + if mant&(1<<flt.mantbits) == 0 { + exp = flt.bias + } + goto out + +overflow: + // ±Inf + mant = 0 + exp = 1<<flt.expbits - 1 + flt.bias + overflow = true + +out: + // Assemble bits. + bits := mant & (uint64(1)<<flt.mantbits - 1) + bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits + if neg { + bits |= 1 << flt.mantbits << flt.expbits + } + return bits, overflow +} + +// Compute exact floating-point integer from d's digits. +// Caller is responsible for avoiding overflow. +func decimalAtof64Int(neg bool, d *decimal) float64 { + f := 0.0 + for i := 0; i < d.nd; i++ { + f = f*10 + float64(d.d[i]-'0') + } + if neg { + f *= -1 // BUG work around 6g f = -f. + } + return f +} + +func decimalAtof32Int(neg bool, d *decimal) float32 { + f := float32(0) + for i := 0; i < d.nd; i++ { + f = f*10 + float32(d.d[i]-'0') + } + if neg { + f *= -1 // BUG work around 6g f = -f. + } + return f +} + +// Exact powers of 10. +var float64pow10 = []float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22, +} +var float32pow10 = []float32{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10} + +// If possible to convert decimal d to 64-bit float f exactly, +// entirely in floating-point math, do so, avoiding the expense of decimalToFloatBits. +// Three common cases: +// value is exact integer +// value is exact integer * exact power of ten +// value is exact integer / exact power of ten +// These all produce potentially inexact but correctly rounded answers. +func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) { + // Exact integers are <= 10^15. + // Exact powers of ten are <= 10^22. + if d.nd > 15 { + return + } + switch { + case d.dp == d.nd: // int + f := decimalAtof64Int(neg, d) + return f, true + + case d.dp > d.nd && d.dp <= 15+22: // int * 10^k + f := decimalAtof64Int(neg, d) + k := d.dp - d.nd + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if k > 22 { + f *= float64pow10[k-22] + k = 22 + } + return f * float64pow10[k], true + + case d.dp < d.nd && d.nd-d.dp <= 22: // int / 10^k + f := decimalAtof64Int(neg, d) + return f / float64pow10[d.nd-d.dp], true + } + return +} + +// If possible to convert decimal d to 32-bit float f exactly, +// entirely in floating-point math, do so, avoiding the machinery above. +func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) { + // Exact integers are <= 10^7. + // Exact powers of ten are <= 10^10. + if d.nd > 7 { + return + } + switch { + case d.dp == d.nd: // int + f := decimalAtof32Int(neg, d) + return f, true + + case d.dp > d.nd && d.dp <= 7+10: // int * 10^k + f := decimalAtof32Int(neg, d) + k := d.dp - d.nd + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if k > 10 { + f *= float32pow10[k-10] + k = 10 + } + return f * float32pow10[k], true + + case d.dp < d.nd && d.nd-d.dp <= 10: // int / 10^k + f := decimalAtof32Int(neg, d) + return f / float32pow10[d.nd-d.dp], true + } + return +} + +// Atof32 converts the string s to a 32-bit floating-point number. +// +// If s is well-formed and near a valid floating point number, +// Atof32 returns the nearest floating point number rounded +// using IEEE754 unbiased rounding. +// +// The errors that Atof32 returns have concrete type *NumError +// and include err.Num = s. +// +// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL. +// +// If s is syntactically well-formed but is more than 1/2 ULP +// away from the largest floating point number of the given size, +// Atof32 returns f = ±Inf, err.Error = os.ERANGE. +func Atof32(s string) (f float32, err os.Error) { + if val, ok := special(s); ok { + return float32(val), nil + } + + neg, d, trunc, ok := stringToDecimal(s) + if !ok { + return 0, &NumError{s, os.EINVAL} + } + if optimize { + if f, ok := decimalAtof32(neg, d, trunc); ok { + return f, nil + } + } + b, ovf := decimalToFloatBits(neg, d, trunc, &float32info) + f = math.Float32frombits(uint32(b)) + if ovf { + err = &NumError{s, os.ERANGE} + } + return f, err +} + +// Atof64 converts the string s to a 64-bit floating-point number. +// Except for the type of its result, its definition is the same as that +// of Atof32. +func Atof64(s string) (f float64, err os.Error) { + if val, ok := special(s); ok { + return val, nil + } + + neg, d, trunc, ok := stringToDecimal(s) + if !ok { + return 0, &NumError{s, os.EINVAL} + } + if optimize { + if f, ok := decimalAtof64(neg, d, trunc); ok { + return f, nil + } + } + b, ovf := decimalToFloatBits(neg, d, trunc, &float64info) + f = math.Float64frombits(b) + if ovf { + err = &NumError{s, os.ERANGE} + } + return f, err +} + +// AtofN converts the string s to a 64-bit floating-point number, +// but it rounds the result assuming that it will be stored in a value +// of n bits (32 or 64). +func AtofN(s string, n int) (f float64, err os.Error) { + if n == 32 { + f1, err1 := Atof32(s) + return float64(f1), err1 + } + f1, err1 := Atof64(s) + return f1, err1 +} diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go new file mode 100644 index 000000000..6cc60e549 --- /dev/null +++ b/libgo/go/strconv/atof_test.go @@ -0,0 +1,183 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "os" + "reflect" + . "strconv" + "testing" +) + +type atofTest struct { + in string + out string + err os.Error +} + +var atoftests = []atofTest{ + {"", "0", os.EINVAL}, + {"1", "1", nil}, + {"+1", "1", nil}, + {"1x", "0", os.EINVAL}, + {"1.1.", "0", os.EINVAL}, + {"1e23", "1e+23", nil}, + {"1E23", "1e+23", nil}, + {"100000000000000000000000", "1e+23", nil}, + {"1e-100", "1e-100", nil}, + {"123456700", "1.234567e+08", nil}, + {"99999999999999974834176", "9.999999999999997e+22", nil}, + {"100000000000000000000001", "1.0000000000000001e+23", nil}, + {"100000000000000008388608", "1.0000000000000001e+23", nil}, + {"100000000000000016777215", "1.0000000000000001e+23", nil}, + {"100000000000000016777216", "1.0000000000000003e+23", nil}, + {"-1", "-1", nil}, + {"-0", "-0", nil}, + {"1e-20", "1e-20", nil}, + {"625e-3", "0.625", nil}, + + // NaNs + {"nan", "NaN", nil}, + {"NaN", "NaN", nil}, + {"NAN", "NaN", nil}, + + // Infs + {"inf", "+Inf", nil}, + {"-Inf", "-Inf", nil}, + {"+INF", "+Inf", nil}, + + // largest float64 + {"1.7976931348623157e308", "1.7976931348623157e+308", nil}, + {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil}, + // next float64 - too large + {"1.7976931348623159e308", "+Inf", os.ERANGE}, + {"-1.7976931348623159e308", "-Inf", os.ERANGE}, + // the border is ...158079 + // borderline - okay + {"1.7976931348623158e308", "1.7976931348623157e+308", nil}, + {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil}, + // borderline - too large + {"1.797693134862315808e308", "+Inf", os.ERANGE}, + {"-1.797693134862315808e308", "-Inf", os.ERANGE}, + + // a little too large + {"1e308", "1e+308", nil}, + {"2e308", "+Inf", os.ERANGE}, + {"1e309", "+Inf", os.ERANGE}, + + // way too large + {"1e310", "+Inf", os.ERANGE}, + {"-1e310", "-Inf", os.ERANGE}, + {"1e400", "+Inf", os.ERANGE}, + {"-1e400", "-Inf", os.ERANGE}, + {"1e400000", "+Inf", os.ERANGE}, + {"-1e400000", "-Inf", os.ERANGE}, + + // denormalized + {"1e-305", "1e-305", nil}, + {"1e-306", "1e-306", nil}, + {"1e-307", "1e-307", nil}, + {"1e-308", "1e-308", nil}, + {"1e-309", "1e-309", nil}, + {"1e-310", "1e-310", nil}, + {"1e-322", "1e-322", nil}, + // smallest denormal + {"5e-324", "5e-324", nil}, + {"4e-324", "5e-324", nil}, + {"3e-324", "5e-324", nil}, + // too small + {"2e-324", "0", nil}, + // way too small + {"1e-350", "0", nil}, + {"1e-400000", "0", nil}, + + // try to overflow exponent + {"1e-4294967296", "0", nil}, + {"1e+4294967296", "+Inf", os.ERANGE}, + {"1e-18446744073709551616", "0", nil}, + {"1e+18446744073709551616", "+Inf", os.ERANGE}, + + // Parse errors + {"1e", "0", os.EINVAL}, + {"1e-", "0", os.EINVAL}, + {".e-1", "0", os.EINVAL}, +} + +func init() { + // The atof routines return NumErrors wrapping + // the error and the string. Convert the table above. + for i := range atoftests { + test := &atoftests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } +} + +func testAtof(t *testing.T, opt bool) { + oldopt := SetOptimize(opt) + for i := 0; i < len(atoftests); i++ { + test := &atoftests[i] + out, err := Atof64(test.in) + outs := Ftoa64(out, 'g', -1) + if outs != test.out || !reflect.DeepEqual(err, test.err) { + t.Errorf("Atof64(%v) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + + out, err = AtofN(test.in, 64) + outs = FtoaN(out, 'g', -1, 64) + if outs != test.out || !reflect.DeepEqual(err, test.err) { + t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + + if float64(float32(out)) == out { + out32, err := Atof32(test.in) + outs := Ftoa32(out32, 'g', -1) + if outs != test.out || !reflect.DeepEqual(err, test.err) { + t.Errorf("Atof32(%v) = %v, %v want %v, %v # %v", + test.in, out32, err, test.out, test.err, out) + } + + out, err := AtofN(test.in, 32) + out32 = float32(out) + outs = FtoaN(float64(out32), 'g', -1, 32) + if outs != test.out || !reflect.DeepEqual(err, test.err) { + t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v", + test.in, out32, err, test.out, test.err, out) + } + } + } + SetOptimize(oldopt) +} + +func TestAtof(t *testing.T) { testAtof(t, true) } + +func TestAtofSlow(t *testing.T) { testAtof(t, false) } + +func BenchmarkAtof64Decimal(b *testing.B) { + for i := 0; i < b.N; i++ { + Atof64("33909") + } +} + +func BenchmarkAtof64Float(b *testing.B) { + for i := 0; i < b.N; i++ { + Atof64("339.7784") + } +} + +func BenchmarkAtof64FloatExp(b *testing.B) { + for i := 0; i < b.N; i++ { + Atof64("-5.09e75") + } +} + +func BenchmarkAtof64Big(b *testing.B) { + for i := 0; i < b.N; i++ { + Atof64("123456789123456789123456789") + } +} diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go new file mode 100644 index 000000000..f7b845672 --- /dev/null +++ b/libgo/go/strconv/atoi.go @@ -0,0 +1,202 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import "os" + +type NumError struct { + Num string + Error os.Error +} + +func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() } + + +func computeIntsize() uint { + siz := uint(8) + for 1<<siz != 0 { + siz *= 2 + } + return siz +} + +var IntSize = computeIntsize() + +// Return the first number n such that n*base >= 1<<64. +func cutoff64(base int) uint64 { + if base < 2 { + return 0 + } + return (1<<64-1)/uint64(base) + 1 +} + +// Btoui64 interprets a string s in an arbitrary base b (2 to 36) +// and returns the corresponding value n. If b == 0, the base +// is taken from the string prefix: base 16 for "0x", base 8 for "0", +// and base 10 otherwise. +// +// The errors that Btoui64 returns have concrete type *NumError +// and include err.Num = s. If s is empty or contains invalid +// digits, err.Error = os.EINVAL; if the value corresponding +// to s cannot be represented by a uint64, err.Error = os.ERANGE. +func Btoui64(s string, b int) (n uint64, err os.Error) { + s0 := s + switch { + case len(s) < 1: + err = os.EINVAL + goto Error + + case 2 <= b && b <= 36: + // valid base; nothing to do + + case b == 0: + // Look for octal, hex prefix. + switch { + case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): + b = 16 + s = s[2:] + if len(s) < 1 { + err = os.EINVAL + goto Error + } + case s[0] == '0': + b = 8 + default: + b = 10 + } + + default: + err = os.ErrorString("invalid base " + Itoa(b)) + goto Error + } + + n = 0 + cutoff := cutoff64(b) + + for i := 0; i < len(s); i++ { + var v byte + d := s[i] + switch { + case '0' <= d && d <= '9': + v = d - '0' + case 'a' <= d && d <= 'z': + v = d - 'a' + 10 + case 'A' <= d && d <= 'Z': + v = d - 'A' + 10 + default: + n = 0 + err = os.EINVAL + goto Error + } + if int(v) >= b { + n = 0 + err = os.EINVAL + goto Error + } + + if n >= cutoff { + // n*b overflows + n = 1<<64 - 1 + err = os.ERANGE + goto Error + } + n *= uint64(b) + + n1 := n + uint64(v) + if n1 < n { + // n+v overflows + n = 1<<64 - 1 + err = os.ERANGE + goto Error + } + n = n1 + } + + return n, nil + +Error: + return n, &NumError{s0, err} +} + +// Atoui64 interprets a string s as a decimal number and +// returns the corresponding value n. +// +// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits. +// It returns err == os.ERANGE if s cannot be represented by a uint64. +func Atoui64(s string) (n uint64, err os.Error) { + return Btoui64(s, 10) +} + +// Btoi64 is like Btoui64 but allows signed numbers and +// returns its result in an int64. +func Btoi64(s string, base int) (i int64, err os.Error) { + // Empty string bad. + if len(s) == 0 { + return 0, &NumError{s, os.EINVAL} + } + + // Pick off leading sign. + s0 := s + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + var un uint64 + un, err = Btoui64(s, base) + if err != nil && err.(*NumError).Error != os.ERANGE { + err.(*NumError).Num = s0 + return 0, err + } + if !neg && un >= 1<<63 { + return 1<<63 - 1, &NumError{s0, os.ERANGE} + } + if neg && un > 1<<63 { + return -1 << 63, &NumError{s0, os.ERANGE} + } + n := int64(un) + if neg { + n = -n + } + return n, nil +} + +// Atoi64 is like Atoui64 but allows signed numbers and +// returns its result in an int64. +func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) } + + +// Atoui is like Atoui64 but returns its result as a uint. +func Atoui(s string) (i uint, err os.Error) { + i1, e1 := Atoui64(s) + if e1 != nil && e1.(*NumError).Error != os.ERANGE { + return 0, e1 + } + i = uint(i1) + if uint64(i) != i1 { + return ^uint(0), &NumError{s, os.ERANGE} + } + return i, nil +} + +// Atoi is like Atoi64 but returns its result as an int. +func Atoi(s string) (i int, err os.Error) { + i1, e1 := Atoi64(s) + if e1 != nil && e1.(*NumError).Error != os.ERANGE { + return 0, e1 + } + i = int(i1) + if int64(i) != i1 { + if i1 < 0 { + return -1 << (IntSize - 1), &NumError{s, os.ERANGE} + } + return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE} + } + return i, nil +} diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go new file mode 100644 index 000000000..0b9f29553 --- /dev/null +++ b/libgo/go/strconv/atoi_test.go @@ -0,0 +1,303 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "os" + "reflect" + . "strconv" + "testing" +) + +type atoui64Test struct { + in string + out uint64 + err os.Error +} + +var atoui64tests = []atoui64Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, os.EINVAL}, + {"98765432100", 98765432100, nil}, + {"18446744073709551615", 1<<64 - 1, nil}, + {"18446744073709551616", 1<<64 - 1, os.ERANGE}, + {"18446744073709551620", 1<<64 - 1, os.ERANGE}, +} + +var btoui64tests = []atoui64Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 012345, nil}, + {"0x12345", 0x12345, nil}, + {"0X12345", 0x12345, nil}, + {"12345x", 0, os.EINVAL}, + {"98765432100", 98765432100, nil}, + {"18446744073709551615", 1<<64 - 1, nil}, + {"18446744073709551616", 1<<64 - 1, os.ERANGE}, + {"18446744073709551620", 1<<64 - 1, os.ERANGE}, + {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil}, + {"0x10000000000000000", 1<<64 - 1, os.ERANGE}, + {"01777777777777777777777", 1<<64 - 1, nil}, + {"01777777777777777777778", 0, os.EINVAL}, + {"02000000000000000000000", 1<<64 - 1, os.ERANGE}, + {"0200000000000000000000", 1 << 61, nil}, +} + +type atoi64Test struct { + in string + out int64 + err os.Error +} + +var atoi64tests = []atoi64Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"98765432100", 98765432100, nil}, + {"-98765432100", -98765432100, nil}, + {"9223372036854775807", 1<<63 - 1, nil}, + {"-9223372036854775807", -(1<<63 - 1), nil}, + {"9223372036854775808", 1<<63 - 1, os.ERANGE}, + {"-9223372036854775808", -1 << 63, nil}, + {"9223372036854775809", 1<<63 - 1, os.ERANGE}, + {"-9223372036854775809", -1 << 63, os.ERANGE}, +} + +var btoi64tests = []atoi64Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 012345, nil}, + {"-012345", -012345, nil}, + {"0x12345", 0x12345, nil}, + {"-0X12345", -0x12345, nil}, + {"12345x", 0, os.EINVAL}, + {"-12345x", 0, os.EINVAL}, + {"98765432100", 98765432100, nil}, + {"-98765432100", -98765432100, nil}, + {"9223372036854775807", 1<<63 - 1, nil}, + {"-9223372036854775807", -(1<<63 - 1), nil}, + {"9223372036854775808", 1<<63 - 1, os.ERANGE}, + {"-9223372036854775808", -1 << 63, nil}, + {"9223372036854775809", 1<<63 - 1, os.ERANGE}, + {"-9223372036854775809", -1 << 63, os.ERANGE}, +} + +type atoui32Test struct { + in string + out uint32 + err os.Error +} + +var atoui32tests = []atoui32Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, os.EINVAL}, + {"987654321", 987654321, nil}, + {"4294967295", 1<<32 - 1, nil}, + {"4294967296", 1<<32 - 1, os.ERANGE}, +} + +type atoi32Test struct { + in string + out int32 + err os.Error +} + +var atoi32tests = []atoi32Test{ + {"", 0, os.EINVAL}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"12345x", 0, os.EINVAL}, + {"-12345x", 0, os.EINVAL}, + {"987654321", 987654321, nil}, + {"-987654321", -987654321, nil}, + {"2147483647", 1<<31 - 1, nil}, + {"-2147483647", -(1<<31 - 1), nil}, + {"2147483648", 1<<31 - 1, os.ERANGE}, + {"-2147483648", -1 << 31, nil}, + {"2147483649", 1<<31 - 1, os.ERANGE}, + {"-2147483649", -1 << 31, os.ERANGE}, +} + +func init() { + // The atoi routines return NumErrors wrapping + // the error and the string. Convert the tables above. + for i := range atoui64tests { + test := &atoui64tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } + for i := range btoui64tests { + test := &btoui64tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } + for i := range atoi64tests { + test := &atoi64tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } + for i := range btoi64tests { + test := &btoi64tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } + for i := range atoui32tests { + test := &atoui32tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } + for i := range atoi32tests { + test := &atoi32tests[i] + if test.err != nil { + test.err = &NumError{test.in, test.err} + } + } +} + +func TestAtoui64(t *testing.T) { + for i := range atoui64tests { + test := &atoui64tests[i] + out, err := Atoui64(test.in) + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoui64(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestBtoui64(t *testing.T) { + for i := range btoui64tests { + test := &btoui64tests[i] + out, err := Btoui64(test.in, 0) + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("Btoui64(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestAtoi64(t *testing.T) { + for i := range atoi64tests { + test := &atoi64tests[i] + out, err := Atoi64(test.in) + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoi64(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestBtoi64(t *testing.T) { + for i := range btoi64tests { + test := &btoi64tests[i] + out, err := Btoi64(test.in, 0) + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("Btoi64(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestAtoui(t *testing.T) { + switch IntSize { + case 32: + for i := range atoui32tests { + test := &atoui32tests[i] + out, err := Atoui(test.in) + if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoui(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range atoui64tests { + test := &atoui64tests[i] + out, err := Atoui(test.in) + if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoui(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func TestAtoi(t *testing.T) { + switch IntSize { + case 32: + for i := range atoi32tests { + test := &atoi32tests[i] + out, err := Atoi(test.in) + if test.out != int32(out) || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range atoi64tests { + test := &atoi64tests[i] + out, err := Atoi(test.in) + if test.out != int64(out) || !reflect.DeepEqual(test.err, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func BenchmarkAtoi(b *testing.B) { + for i := 0; i < b.N; i++ { + Atoi("12345678") + } +} + +func BenchmarkAtoiNeg(b *testing.B) { + for i := 0; i < b.N; i++ { + Atoi("-12345678") + } +} + +func BenchmarkAtoi64(b *testing.B) { + for i := 0; i < b.N; i++ { + Atoi64("12345678901234") + } +} + +func BenchmarkAtoi64Neg(b *testing.B) { + for i := 0; i < b.N; i++ { + Atoi64("-12345678901234") + } +} diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go new file mode 100644 index 000000000..3a5cf1ba6 --- /dev/null +++ b/libgo/go/strconv/decimal.go @@ -0,0 +1,371 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package strconv + +type decimal struct { + // TODO(rsc): Can make d[] a bit smaller and add + // truncated bool; + d [2000]byte // digits + nd int // number of digits used + dp int // decimal point +} + +func (a *decimal) String() string { + n := 10 + a.nd + if a.dp > 0 { + n += a.dp + } + if a.dp < 0 { + n += -a.dp + } + + buf := make([]byte, n) + w := 0 + switch { + case a.nd == 0: + return "0" + + case a.dp <= 0: + // zeros fill space between decimal point and digits + buf[w] = '0' + w++ + buf[w] = '.' + w++ + w += digitZero(buf[w : w+-a.dp]) + w += copy(buf[w:], a.d[0:a.nd]) + + case a.dp < a.nd: + // decimal point in middle of digits + w += copy(buf[w:], a.d[0:a.dp]) + buf[w] = '.' + w++ + w += copy(buf[w:], a.d[a.dp:a.nd]) + + default: + // zeros fill space between digits and decimal point + w += copy(buf[w:], a.d[0:a.nd]) + w += digitZero(buf[w : w+a.dp-a.nd]) + } + return string(buf[0:w]) +} + +func digitZero(dst []byte) int { + for i := range dst { + dst[i] = '0' + } + return len(dst) +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [50]byte + + // Write reversed decimal in buf. + n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0 + for n--; n >= 0; n-- { + a.d[a.nd] = buf[n] + a.nd++ + } + a.dp = a.nd + trim(a) +} + +func newDecimal(i uint64) *decimal { + a := new(decimal) + a.Assign(i) + return a +} + +// Maximum shift that we can do in one pass without overflow. +// Signed int has 31 bits, and we have to be able to accomodate 9<<k. +const maxShift = 27 + +// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow. +func rightShift(a *decimal, k uint) { + r := 0 // read pointer + w := 0 // write pointer + + // Pick up enough leading digits to cover first shift. + n := 0 + for ; n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + return + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := int(a.d[r]) + n = n*10 + c - '0' + } + a.dp -= r - 1 + + // Pick up a digit, put down a digit. + for ; r < a.nd; r++ { + c := int(a.d[r]) + dig := n >> k + n -= dig << k + a.d[w] = byte(dig + '0') + w++ + n = n*10 + c - '0' + } + + // Put down extra digits. + for n > 0 { + dig := n >> k + n -= dig << k + a.d[w] = byte(dig + '0') + w++ + n = n * 10 + } + + a.nd = w + trim(a) +} + +// Cheat sheet for left shift: table indexed by shift count giving +// number of new digits that will be introduced by that shift. +// +// For example, leftcheats[4] = {2, "625"}. That means that +// if we are shifting by 4 (multiplying by 16), it will add 2 digits +// when the string prefix is "625" through "999", and one fewer digit +// if the string prefix is "000" through "624". +// +// Credit for this trick goes to Ken. + +type leftCheat struct { + delta int // number of new digits + cutoff string // minus one digit if original < a. +} + +var leftcheats = []leftCheat{ + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + /* + seq 27 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," } + { + log2 = log(2)/log(10) + printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n", + int(log2*NR+1), $0, 2**NR) + }' + */ + {0, ""}, + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 +} + +// Is the leading prefix of b lexicographically less than s? +func prefixIsLessThan(b []byte, s string) bool { + for i := 0; i < len(s); i++ { + if i >= len(b) { + return true + } + if b[i] != s[i] { + return b[i] < s[i] + } + } + return false +} + +// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow. +func leftShift(a *decimal, k uint) { + delta := leftcheats[k].delta + if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { + delta-- + } + + r := a.nd // read index + w := a.nd + delta // write index + n := 0 + + // Pick up a digit, put down a digit. + for r--; r >= 0; r-- { + n += (int(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10*quo + w-- + a.d[w] = byte(rem + '0') + n = quo + } + + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10*quo + w-- + a.d[w] = byte(rem + '0') + n = quo + } + + a.nd += delta + a.dp += delta + trim(a) +} + +// Binary shift left (k > 0) or right (k < 0). +// Returns receiver for convenience. +func (a *decimal) Shift(k int) *decimal { + switch { + case a.nd == 0: + // nothing to do: a == 0 + case k > 0: + for k > maxShift { + leftShift(a, maxShift) + k -= maxShift + } + leftShift(a, uint(k)) + case k < 0: + for k < -maxShift { + rightShift(a, maxShift) + k += maxShift + } + rightShift(a, uint(-k)) + } + return a +} + +// If we chop a at nd digits, should we round up? +func shouldRoundUp(a *decimal, nd int) bool { + if nd < 0 || nd >= a.nd { + return false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + return nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + return a.d[nd] >= '5' +} + +// 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. +func (a *decimal) Round(nd int) *decimal { + if nd < 0 || nd >= a.nd { + return a + } + if shouldRoundUp(a, nd) { + return a.RoundUp(nd) + } + return a.RoundDown(nd) +} + +// Round a down to nd digits (or fewer). +// Returns receiver for convenience. +func (a *decimal) RoundDown(nd int) *decimal { + if nd < 0 || nd >= a.nd { + return a + } + a.nd = nd + trim(a) + return a +} + +// Round a up to nd digits (or fewer). +// Returns receiver for convenience. +func (a *decimal) RoundUp(nd int) *decimal { + if nd < 0 || nd >= a.nd { + return a + } + + // round up + for i := nd - 1; i >= 0; i-- { + c := a.d[i] + if c < '9' { // can stop after this digit + a.d[i]++ + a.nd = i + 1 + return a + } + } + + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + a.d[0] = '1' + a.nd = 1 + a.dp++ + return a +} + +// Extract integer part, rounded appropriately. +// No guarantees about overflow. +func (a *decimal) RoundedInteger() uint64 { + if a.dp > 20 { + return 0xFFFFFFFFFFFFFFFF + } + var i int + n := uint64(0) + for i = 0; i < a.dp && i < a.nd; i++ { + n = n*10 + uint64(a.d[i]-'0') + } + for ; i < a.dp; i++ { + n *= 10 + } + if shouldRoundUp(a, a.dp) { + n++ + } + return n +} diff --git a/libgo/go/strconv/decimal_test.go b/libgo/go/strconv/decimal_test.go new file mode 100644 index 000000000..9b7903516 --- /dev/null +++ b/libgo/go/strconv/decimal_test.go @@ -0,0 +1,117 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + . "strconv" + "testing" +) + +type shiftTest struct { + i uint64 + shift int + out string +} + +var shifttests = []shiftTest{ + {0, -100, "0"}, + {0, 100, "0"}, + {1, 100, "1267650600228229401496703205376"}, + {1, -100, + "0.00000000000000000000000000000078886090522101180541" + + "17285652827862296732064351090230047702789306640625", + }, + {12345678, 8, "3160493568"}, + {12345678, -8, "48225.3046875"}, + {195312, 9, "99999744"}, + {1953125, 9, "1000000000"}, +} + +func TestDecimalShift(t *testing.T) { + for i := 0; i < len(shifttests); i++ { + test := &shifttests[i] + s := NewDecimal(test.i).Shift(test.shift).String() + if s != test.out { + t.Errorf("Decimal %v << %v = %v, want %v", + test.i, test.shift, s, test.out) + } + } +} + +type roundTest struct { + i uint64 + nd int + down, round, up string + int uint64 +} + +var roundtests = []roundTest{ + {0, 4, "0", "0", "0", 0}, + {12344999, 4, "12340000", "12340000", "12350000", 12340000}, + {12345000, 4, "12340000", "12340000", "12350000", 12340000}, + {12345001, 4, "12340000", "12350000", "12350000", 12350000}, + {23454999, 4, "23450000", "23450000", "23460000", 23450000}, + {23455000, 4, "23450000", "23460000", "23460000", 23460000}, + {23455001, 4, "23450000", "23460000", "23460000", 23460000}, + + {99994999, 4, "99990000", "99990000", "100000000", 99990000}, + {99995000, 4, "99990000", "100000000", "100000000", 100000000}, + {99999999, 4, "99990000", "100000000", "100000000", 100000000}, + + {12994999, 4, "12990000", "12990000", "13000000", 12990000}, + {12995000, 4, "12990000", "13000000", "13000000", 13000000}, + {12999999, 4, "12990000", "13000000", "13000000", 13000000}, +} + +func TestDecimalRound(t *testing.T) { + for i := 0; i < len(roundtests); i++ { + test := &roundtests[i] + s := NewDecimal(test.i).RoundDown(test.nd).String() + if s != test.down { + t.Errorf("Decimal %v RoundDown %d = %v, want %v", + test.i, test.nd, s, test.down) + } + s = NewDecimal(test.i).Round(test.nd).String() + if s != test.round { + t.Errorf("Decimal %v Round %d = %v, want %v", + test.i, test.nd, s, test.down) + } + s = NewDecimal(test.i).RoundUp(test.nd).String() + if s != test.up { + t.Errorf("Decimal %v RoundUp %d = %v, want %v", + test.i, test.nd, s, test.up) + } + } +} + +type roundIntTest struct { + i uint64 + shift int + int uint64 +} + +var roundinttests = []roundIntTest{ + {0, 100, 0}, + {512, -8, 2}, + {513, -8, 2}, + {640, -8, 2}, + {641, -8, 3}, + {384, -8, 2}, + {385, -8, 2}, + {383, -8, 1}, + {1, 100, 1<<64 - 1}, + {1000, 0, 1000}, +} + +func TestDecimalRoundedInteger(t *testing.T) { + for i := 0; i < len(roundinttests); i++ { + test := roundinttests[i] + int := NewDecimal(test.i).Shift(test.shift).RoundedInteger() + if int != test.int { + t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v", + test.i, test.shift, int, test.int) + } + } +} diff --git a/libgo/go/strconv/fp_test.go b/libgo/go/strconv/fp_test.go new file mode 100644 index 000000000..305adcc0c --- /dev/null +++ b/libgo/go/strconv/fp_test.go @@ -0,0 +1,149 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + "testing" +) + +func pow2(i int) float64 { + switch { + case i < 0: + return 1 / pow2(-i) + case i == 0: + return 1 + case i == 1: + return 2 + } + return pow2(i/2) * pow2(i-i/2) +} + +// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.Atof64. +func myatof64(s string) (f float64, ok bool) { + a := strings.Split(s, "p", 2) + if len(a) == 2 { + n, err := strconv.Atoi64(a[0]) + if err != nil { + return 0, false + } + e, err1 := strconv.Atoi(a[1]) + if err1 != nil { + println("bad e", a[1]) + return 0, false + } + v := float64(n) + // We expect that v*pow2(e) fits in a float64, + // but pow2(e) by itself may not. Be careful. + if e <= -1000 { + v *= pow2(-1000) + e += 1000 + for e < 0 { + v /= 2 + e++ + } + return v, true + } + if e >= 1000 { + v *= pow2(1000) + e -= 1000 + for e > 0 { + v *= 2 + e-- + } + return v, true + } + return v * pow2(e), true + } + f1, err := strconv.Atof64(s) + if err != nil { + return 0, false + } + return f1, true +} + +// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.Atof32. +func myatof32(s string) (f float32, ok bool) { + a := strings.Split(s, "p", 2) + if len(a) == 2 { + n, err := strconv.Atoi(a[0]) + if err != nil { + println("bad n", a[0]) + return 0, false + } + e, err1 := strconv.Atoi(a[1]) + if err1 != nil { + println("bad p", a[1]) + return 0, false + } + return float32(float64(n) * pow2(e)), true + } + f1, err1 := strconv.Atof32(s) + if err1 != nil { + return 0, false + } + return f1, true +} + +func TestFp(t *testing.T) { + f, err := os.Open("testfp.txt", os.O_RDONLY, 0) + if err != nil { + t.Fatal("testfp: open testfp.txt:", err.String()) + } + defer f.Close() + + b := bufio.NewReader(f) + + lineno := 0 + for { + line, err2 := b.ReadString('\n') + if err2 == os.EOF { + break + } + if err2 != nil { + t.Fatal("testfp: read testfp.txt: " + err2.String()) + } + line = line[0 : len(line)-1] + lineno++ + if len(line) == 0 || line[0] == '#' { + continue + } + a := strings.Split(line, " ", -1) + if len(a) != 4 { + t.Error("testfp.txt:", lineno, ": wrong field count") + continue + } + var s string + var v float64 + switch a[0] { + case "float64": + var ok bool + v, ok = myatof64(a[2]) + if !ok { + t.Error("testfp.txt:", lineno, ": cannot atof64 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v) + case "float32": + v1, ok := myatof32(a[2]) + if !ok { + t.Error("testfp.txt:", lineno, ": cannot atof32 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v1) + v = float64(v1) + } + if s != a[3] { + t.Error("testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ", + "want ", a[3], " got ", s) + } + } +} diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go new file mode 100644 index 000000000..4ec3cdbb9 --- /dev/null +++ b/libgo/go/strconv/ftoa.go @@ -0,0 +1,405 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Binary to decimal floating point conversion. +// Algorithm: +// 1) store mantissa in multiprecision decimal +// 2) shift decimal by exponent +// 3) read digits out & format + +package strconv + +import "math" + +// TODO: move elsewhere? +type floatInfo struct { + mantbits uint + expbits uint + bias int +} + +var float32info = floatInfo{23, 8, -127} +var float64info = floatInfo{52, 11, -1023} + +// Ftoa32 converts the 32-bit floating-point number f to a string, +// according to the format fmt and precision prec. +// +// The format fmt is one of +// 'b' (-ddddp±ddd, a binary exponent), +// 'e' (-d.dddde±dd, a decimal exponent), +// 'E' (-d.ddddE±dd, a decimal exponent), +// 'f' (-ddd.dddd, no exponent), +// 'g' ('e' for large exponents, 'f' otherwise), or +// 'G' ('E' for large exponents, 'f' otherwise). +// +// The precision prec controls the number of digits +// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats. +// For 'e', 'E', and 'f' it is the number of digits after the decimal point. +// For 'g' and 'G' it is the total number of digits. +// The special precision -1 uses the smallest number of digits +// necessary such that Atof32 will return f exactly. +// +// Ftoa32(f) is not the same as Ftoa64(float32(f)), +// because correct rounding and the number of digits +// needed to identify f depend on the precision of the representation. +func Ftoa32(f float32, fmt byte, prec int) string { + return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info) +} + +// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number. +func Ftoa64(f float64, fmt byte, prec int) string { + return genericFtoa(math.Float64bits(f), fmt, prec, &float64info) +} + +// FtoaN converts the 64-bit floating-point number f to a string, +// according to the format fmt and precision prec, but it rounds the +// result assuming that it was obtained from a floating-point value +// of n bits (32 or 64). +func FtoaN(f float64, fmt byte, prec int, n int) string { + if n == 32 { + return Ftoa32(float32(f), fmt, prec) + } + return Ftoa64(f, fmt, prec) +} + +func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string { + neg := bits>>flt.expbits>>flt.mantbits != 0 + exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1) + mant := bits & (uint64(1)<<flt.mantbits - 1) + + switch exp { + case 1<<flt.expbits - 1: + // Inf, NaN + if mant != 0 { + return "NaN" + } + if neg { + return "-Inf" + } + return "+Inf" + + case 0: + // denormalized + exp++ + + default: + // add implicit top bit + mant |= uint64(1) << flt.mantbits + } + exp += flt.bias + + // Pick off easy binary format. + if fmt == 'b' { + return fmtB(neg, mant, exp, flt) + } + + // Create exact decimal representation. + // The shift is exp - flt.mantbits because mant is a 1-bit integer + // followed by a flt.mantbits fraction, and we are treating it as + // a 1+flt.mantbits-bit integer. + d := newDecimal(mant).Shift(exp - int(flt.mantbits)) + + // Round appropriately. + // Negative precision means "only as much as needed to be exact." + shortest := false + if prec < 0 { + shortest = true + roundShortest(d, mant, exp, flt) + switch fmt { + case 'e', 'E': + prec = d.nd - 1 + case 'f': + prec = max(d.nd-d.dp, 0) + case 'g', 'G': + prec = d.nd + } + } else { + switch fmt { + case 'e', 'E': + d.Round(prec + 1) + case 'f': + d.Round(d.dp + prec) + case 'g', 'G': + if prec == 0 { + prec = 1 + } + d.Round(prec) + } + } + + switch fmt { + case 'e', 'E': + return fmtE(neg, d, prec, fmt) + case 'f': + return fmtF(neg, d, prec) + case 'g', 'G': + // trailing fractional zeros in 'e' form will be trimmed. + eprec := prec + if eprec > d.nd && d.nd >= d.dp { + eprec = d.nd + } + // %e is used if the exponent from the conversion + // is less than -4 or greater than or equal to the precision. + // if precision was the shortest possible, use precision 6 for this decision. + if shortest { + eprec = 6 + } + exp := d.dp - 1 + if exp < -4 || exp >= eprec { + if prec > d.nd { + prec = d.nd + } + return fmtE(neg, d, prec-1, fmt+'e'-'g') + } + if prec > d.dp { + prec = d.nd + } + return fmtF(neg, d, max(prec-d.dp, 0)) + } + + return "%" + string(fmt) +} + +// Round d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely +// reconstructed. Size is original floating point size (64 or 32). +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + return + } + + // TODO(rsc): Unless exp == minexp, if the number of digits in d + // is less than 17, it seems likely that it would be + // the shortest possible number already. So maybe we can + // bail out without doing the extra multiprecision math here. + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1. + upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1. + minexp := flt.bias + 1 // minimum possible exponent + var mantlo uint64 + var explo int + if mant > 1<<flt.mantbits || exp == minexp { + mantlo = mant - 1 + explo = exp + } else { + mantlo = mant*2 - 1 + explo = exp - 1 + } + lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1) + + // The upper and lower bounds are possible outputs only if + // the original mantissa is even, so that IEEE round-to-even + // would round to the original mantissa and not the neighbors. + inclusive := mant%2 == 0 + + // Now we can figure out the minimum number of digits required. + // Walk along until d has distinguished itself from upper and lower. + for i := 0; i < d.nd; i++ { + var l, m, u byte // lower, middle, upper digits + if i < lower.nd { + l = lower.d[i] + } else { + l = '0' + } + m = d.d[i] + if i < upper.nd { + u = upper.d[i] + } else { + u = '0' + } + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding down. + okdown := l != m || (inclusive && l == m && i+1 == lower.nd) + + // Okay to round up if upper has a different digit and + // either upper is inclusive or upper is bigger than the result of rounding up. + okup := m != u && (inclusive || i+1 < upper.nd) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + switch { + case okdown && okup: + d.Round(i + 1) + return + case okdown: + d.RoundDown(i + 1) + return + case okup: + d.RoundUp(i + 1) + return + } + } +} + +// %e: -d.ddddde±dd +func fmtE(neg bool, d *decimal, prec int, fmt byte) string { + buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp + w := 0 // write index + + // sign + if neg { + buf[w] = '-' + w++ + } + + // first digit + if d.nd == 0 { + buf[w] = '0' + } else { + buf[w] = d.d[0] + } + w++ + + // .moredigits + if prec > 0 { + buf[w] = '.' + w++ + for i := 0; i < prec; i++ { + if 1+i < d.nd { + buf[w] = d.d[1+i] + } else { + buf[w] = '0' + } + w++ + } + } + + // e± + buf[w] = fmt + w++ + exp := d.dp - 1 + if d.nd == 0 { // special case: 0 has exponent 0 + exp = 0 + } + if exp < 0 { + buf[w] = '-' + exp = -exp + } else { + buf[w] = '+' + } + w++ + + // dddd + // count digits + n := 0 + for e := exp; e > 0; e /= 10 { + n++ + } + // leading zeros + for i := n; i < 2; i++ { + buf[w] = '0' + w++ + } + // digits + w += n + n = 0 + for e := exp; e > 0; e /= 10 { + n++ + buf[w-n] = byte(e%10 + '0') + } + + return string(buf[0:w]) +} + +// %f: -ddddddd.ddddd +func fmtF(neg bool, d *decimal, prec int) string { + buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0)) + w := 0 + + // sign + if neg { + buf[w] = '-' + w++ + } + + // integer, padded with zeros as needed. + if d.dp > 0 { + var i int + for i = 0; i < d.dp && i < d.nd; i++ { + buf[w] = d.d[i] + w++ + } + for ; i < d.dp; i++ { + buf[w] = '0' + w++ + } + } else { + buf[w] = '0' + w++ + } + + // fraction + if prec > 0 { + buf[w] = '.' + w++ + for i := 0; i < prec; i++ { + if d.dp+i < 0 || d.dp+i >= d.nd { + buf[w] = '0' + } else { + buf[w] = d.d[d.dp+i] + } + w++ + } + } + + return string(buf[0:w]) +} + +// %b: -ddddddddp+ddd +func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string { + var buf [50]byte + w := len(buf) + exp -= int(flt.mantbits) + esign := byte('+') + if exp < 0 { + esign = '-' + exp = -exp + } + n := 0 + for exp > 0 || n < 1 { + n++ + w-- + buf[w] = byte(exp%10 + '0') + exp /= 10 + } + w-- + buf[w] = esign + w-- + buf[w] = 'p' + n = 0 + for mant > 0 || n < 1 { + n++ + w-- + buf[w] = byte(mant%10 + '0') + mant /= 10 + } + if neg { + w-- + buf[w] = '-' + } + return string(buf[w:]) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go new file mode 100644 index 000000000..3a862a2be --- /dev/null +++ b/libgo/go/strconv/ftoa_test.go @@ -0,0 +1,145 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "math" + . "strconv" + "testing" +) + +type ftoaTest struct { + f float64 + fmt byte + prec int + s string +} + +func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark + +const ( + below1e23 = 99999999999999974834176 + above1e23 = 100000000000000008388608 +) + +var ftoatests = []ftoaTest{ + {1, 'e', 5, "1.00000e+00"}, + {1, 'f', 5, "1.00000"}, + {1, 'g', 5, "1"}, + {1, 'g', -1, "1"}, + {20, 'g', -1, "20"}, + {1234567.8, 'g', -1, "1.2345678e+06"}, + {200000, 'g', -1, "200000"}, + {2000000, 'g', -1, "2e+06"}, + + // g conversion and zero suppression + {400, 'g', 2, "4e+02"}, + {40, 'g', 2, "40"}, + {4, 'g', 2, "4"}, + {.4, 'g', 2, "0.4"}, + {.04, 'g', 2, "0.04"}, + {.004, 'g', 2, "0.004"}, + {.0004, 'g', 2, "0.0004"}, + {.00004, 'g', 2, "4e-05"}, + {.000004, 'g', 2, "4e-06"}, + + {0, 'e', 5, "0.00000e+00"}, + {0, 'f', 5, "0.00000"}, + {0, 'g', 5, "0"}, + {0, 'g', -1, "0"}, + + {-1, 'e', 5, "-1.00000e+00"}, + {-1, 'f', 5, "-1.00000"}, + {-1, 'g', 5, "-1"}, + {-1, 'g', -1, "-1"}, + + {12, 'e', 5, "1.20000e+01"}, + {12, 'f', 5, "12.00000"}, + {12, 'g', 5, "12"}, + {12, 'g', -1, "12"}, + + {123456700, 'e', 5, "1.23457e+08"}, + {123456700, 'f', 5, "123456700.00000"}, + {123456700, 'g', 5, "1.2346e+08"}, + {123456700, 'g', -1, "1.234567e+08"}, + + {1.2345e6, 'e', 5, "1.23450e+06"}, + {1.2345e6, 'f', 5, "1234500.00000"}, + {1.2345e6, 'g', 5, "1.2345e+06"}, + + {1e23, 'e', 17, "9.99999999999999916e+22"}, + {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, + {1e23, 'g', 17, "9.9999999999999992e+22"}, + + {1e23, 'e', -1, "1e+23"}, + {1e23, 'f', -1, "100000000000000000000000"}, + {1e23, 'g', -1, "1e+23"}, + + {below1e23, 'e', 17, "9.99999999999999748e+22"}, + {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, + {below1e23, 'g', 17, "9.9999999999999975e+22"}, + + {below1e23, 'e', -1, "9.999999999999997e+22"}, + {below1e23, 'f', -1, "99999999999999970000000"}, + {below1e23, 'g', -1, "9.999999999999997e+22"}, + + {above1e23, 'e', 17, "1.00000000000000008e+23"}, + {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, + {above1e23, 'g', 17, "1.0000000000000001e+23"}, + + {above1e23, 'e', -1, "1.0000000000000001e+23"}, + {above1e23, 'f', -1, "100000000000000010000000"}, + {above1e23, 'g', -1, "1.0000000000000001e+23"}, + + {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, + {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, + + {32, 'g', -1, "32"}, + {32, 'g', 0, "3e+01"}, + + {100, 'x', -1, "%x"}, + + {math.NaN(), 'g', -1, "NaN"}, + {-math.NaN(), 'g', -1, "NaN"}, + {math.Inf(0), 'g', -1, "+Inf"}, + {math.Inf(-1), 'g', -1, "-Inf"}, + {-math.Inf(0), 'g', -1, "-Inf"}, + + {-1, 'b', -1, "-4503599627370496p-52"}, + + // fixed bugs + {0.9, 'f', 1, "0.9"}, + {0.09, 'f', 1, "0.1"}, + {0.0999, 'f', 1, "0.1"}, + {0.05, 'f', 1, "0.1"}, + {0.05, 'f', 0, "0"}, + {0.5, 'f', 1, "0.5"}, + {0.5, 'f', 0, "0"}, + {1.5, 'f', 0, "2"}, +} + +func TestFtoa(t *testing.T) { + for i := 0; i < len(ftoatests); i++ { + test := &ftoatests[i] + s := Ftoa64(test.f, test.fmt, test.prec) + if s != test.s { + t.Error("test", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + s = FtoaN(test.f, test.fmt, test.prec, 64) + if s != test.s { + t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + if float64(float32(test.f)) == test.f && test.fmt != 'b' { + s := Ftoa32(float32(test.f), test.fmt, test.prec) + if s != test.s { + t.Error("test32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + s = FtoaN(test.f, test.fmt, test.prec, 32) + if s != test.s { + t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + } + } +} diff --git a/libgo/go/strconv/internal_test.go b/libgo/go/strconv/internal_test.go new file mode 100644 index 000000000..9a7f4f086 --- /dev/null +++ b/libgo/go/strconv/internal_test.go @@ -0,0 +1,15 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// export access to strconv internals for tests + +package strconv + +func NewDecimal(i uint64) *decimal { return newDecimal(i) } + +func SetOptimize(b bool) bool { + old := optimize + optimize = b + return old +} diff --git a/libgo/go/strconv/itoa.go b/libgo/go/strconv/itoa.go new file mode 100644 index 000000000..a0a749664 --- /dev/null +++ b/libgo/go/strconv/itoa.go @@ -0,0 +1,57 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +// Uitob64 returns the string representation of i in the given base. +func Uitob64(u uint64, base uint) string { + if base < 2 || 36 < base { + panic("invalid base " + Uitoa(base)) + } + if u == 0 { + return "0" + } + + // Assemble decimal in reverse order. + var buf [64]byte + j := len(buf) + b := uint64(base) + for u > 0 { + j-- + buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b] + u /= b + } + + return string(buf[j:]) +} + +// Itob64 returns the string representation of i in the given base. +func Itob64(i int64, base uint) string { + if i == 0 { + return "0" + } + + if i < 0 { + return "-" + Uitob64(-uint64(i), base) + } + return Uitob64(uint64(i), base) +} + +// Itoa64 returns the decimal string representation of i. +func Itoa64(i int64) string { return Itob64(i, 10) } + +// Uitoa64 returns the decimal string representation of i. +func Uitoa64(i uint64) string { return Uitob64(i, 10) } + +// Uitob returns the string representation of i in the given base. +func Uitob(i uint, base uint) string { return Uitob64(uint64(i), base) } + +// Itob returns the string representation of i in the given base. +func Itob(i int, base uint) string { return Itob64(int64(i), base) } + +// Itoa returns the decimal string representation of i. +func Itoa(i int) string { return Itob64(int64(i), 10) } + +// Uitoa returns the decimal string representation of i. +func Uitoa(i uint) string { return Uitob64(uint64(i), 10) } diff --git a/libgo/go/strconv/itoa_test.go b/libgo/go/strconv/itoa_test.go new file mode 100644 index 000000000..8514b21e4 --- /dev/null +++ b/libgo/go/strconv/itoa_test.go @@ -0,0 +1,174 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + . "strconv" + "testing" +) + +type itob64Test struct { + in int64 + base uint + out string +} + +var itob64tests = []itob64Test{ + {0, 10, "0"}, + {1, 10, "1"}, + {-1, 10, "-1"}, + {12345678, 10, "12345678"}, + {-987654321, 10, "-987654321"}, + {1<<31 - 1, 10, "2147483647"}, + {-1<<31 + 1, 10, "-2147483647"}, + {1 << 31, 10, "2147483648"}, + {-1 << 31, 10, "-2147483648"}, + {1<<31 + 1, 10, "2147483649"}, + {-1<<31 - 1, 10, "-2147483649"}, + {1<<32 - 1, 10, "4294967295"}, + {-1<<32 + 1, 10, "-4294967295"}, + {1 << 32, 10, "4294967296"}, + {-1 << 32, 10, "-4294967296"}, + {1<<32 + 1, 10, "4294967297"}, + {-1<<32 - 1, 10, "-4294967297"}, + {1 << 50, 10, "1125899906842624"}, + {1<<63 - 1, 10, "9223372036854775807"}, + {-1<<63 + 1, 10, "-9223372036854775807"}, + {-1 << 63, 10, "-9223372036854775808"}, + + {0, 2, "0"}, + {10, 2, "1010"}, + {-1, 2, "-1"}, + {1 << 15, 2, "1000000000000000"}, + + {-8, 8, "-10"}, + {057635436545, 8, "57635436545"}, + {1 << 24, 8, "100000000"}, + + {16, 16, "10"}, + {-0x123456789abcdef, 16, "-123456789abcdef"}, + {1<<63 - 1, 16, "7fffffffffffffff"}, + {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"}, + + {16, 17, "g"}, + {25, 25, "10"}, + {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"}, + {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"}, +} + +func TestItoa(t *testing.T) { + for _, test := range itob64tests { + s := Itob64(test.in, test.base) + if s != test.out { + t.Errorf("Itob64(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + + if test.in >= 0 { + s := Uitob64(uint64(test.in), test.base) + if s != test.out { + t.Errorf("Uitob64(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + } + + if int64(int(test.in)) == test.in { + s := Itob(int(test.in), test.base) + if s != test.out { + t.Errorf("Itob(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + + if test.in >= 0 { + s := Uitob(uint(test.in), test.base) + if s != test.out { + t.Errorf("Uitob(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + } + } + + if test.base == 10 { + s := Itoa64(test.in) + if s != test.out { + t.Errorf("Itoa64(%v) = %v want %v", + test.in, s, test.out) + } + + if test.in >= 0 { + s := Uitob64(uint64(test.in), test.base) + if s != test.out { + t.Errorf("Uitob64(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + } + + if int64(int(test.in)) == test.in { + s := Itoa(int(test.in)) + if s != test.out { + t.Errorf("Itoa(%v) = %v want %v", + test.in, s, test.out) + } + + if test.in >= 0 { + s := Uitoa(uint(test.in)) + if s != test.out { + t.Errorf("Uitoa(%v) = %v want %v", + test.in, s, test.out) + } + } + } + } + } +} + +type uitob64Test struct { + in uint64 + base uint + out string +} + +var uitob64tests = []uitob64Test{ + {1<<63 - 1, 10, "9223372036854775807"}, + {1 << 63, 10, "9223372036854775808"}, + {1<<63 + 1, 10, "9223372036854775809"}, + {1<<64 - 2, 10, "18446744073709551614"}, + {1<<64 - 1, 10, "18446744073709551615"}, + {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"}, +} + +func TestUitoa(t *testing.T) { + for _, test := range uitob64tests { + s := Uitob64(test.in, test.base) + if s != test.out { + t.Errorf("Uitob64(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + + if uint64(uint(test.in)) == test.in { + s := Uitob(uint(test.in), test.base) + if s != test.out { + t.Errorf("Uitob(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + } + + if test.base == 10 { + s := Uitoa64(test.in) + if s != test.out { + t.Errorf("Uitoa64(%v) = %v want %v", + test.in, s, test.out) + } + + if uint64(uint(test.in)) == test.in { + s := Uitoa(uint(test.in)) + if s != test.out { + t.Errorf("Uitoa(%v) = %v want %v", + test.in, s, test.out) + } + } + } + } +} diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go new file mode 100644 index 000000000..ed5889723 --- /dev/null +++ b/libgo/go/strconv/quote.go @@ -0,0 +1,264 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "bytes" + "os" + "strings" + "unicode" + "utf8" +) + +const lowerhex = "0123456789abcdef" + +// Quote returns a double-quoted Go string literal +// representing s. The returned string s uses Go escape +// sequences (\t, \n, \xFF, \u0100) for control characters +// and non-ASCII characters. +func Quote(s string) string { + var buf bytes.Buffer + buf.WriteByte('"') + for ; len(s) > 0; s = s[1:] { + switch c := s[0]; { + case c == '"': + buf.WriteString(`\"`) + case c == '\\': + buf.WriteString(`\\`) + case ' ' <= c && c <= '~': + buf.WriteString(string(c)) + case c == '\a': + buf.WriteString(`\a`) + case c == '\b': + buf.WriteString(`\b`) + case c == '\f': + buf.WriteString(`\f`) + case c == '\n': + buf.WriteString(`\n`) + case c == '\r': + buf.WriteString(`\r`) + case c == '\t': + buf.WriteString(`\t`) + case c == '\v': + buf.WriteString(`\v`) + + case c >= utf8.RuneSelf && utf8.FullRuneInString(s): + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && size == 1 { + goto EscX + } + s = s[size-1:] // next iteration will slice off 1 more + if r < 0x10000 { + buf.WriteString(`\u`) + for j := uint(0); j < 4; j++ { + buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF]) + } + } else { + buf.WriteString(`\U`) + for j := uint(0); j < 8; j++ { + buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF]) + } + } + + default: + EscX: + buf.WriteString(`\x`) + buf.WriteByte(lowerhex[c>>4]) + buf.WriteByte(lowerhex[c&0xF]) + } + } + buf.WriteByte('"') + return buf.String() +} + +// CanBackquote returns whether the string s would be +// a valid Go string literal if enclosed in backquotes. +func CanBackquote(s string) bool { + for i := 0; i < len(s); i++ { + if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' { + return false + } + } + return true +} + +func unhex(b byte) (v int, ok bool) { + c := int(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +// UnquoteChar decodes the first character or byte in the escaped string +// or character literal represented by the string s. +// It returns four values: +// +// 1) value, the decoded Unicode code point or byte value; +// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation; +// 3) tail, the remainder of the string after the character; and +// 4) an error that will be nil if the character is syntactically valid. +// +// The second argument, quote, specifies the type of literal being parsed +// and therefore which escaped quote character is permitted. +// If set to a single quote, it permits the sequence \' and disallows unescaped '. +// If set to a double quote, it permits \" and disallows unescaped ". +// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped. +func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) { + // easy cases + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = os.EINVAL + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return int(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = os.EINVAL + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + v := 0 + if len(s) < n { + err = os.EINVAL + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = os.EINVAL + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if v > unicode.MaxRune { + err = os.EINVAL + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := int(c) - '0' + if len(s) < 2 { + err = os.EINVAL + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := int(s[j]) - '0' + if x < 0 || x > 7 { + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = os.EINVAL + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = os.EINVAL + return + } + value = int(c) + default: + err = os.EINVAL + return + } + tail = s + return +} + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (t string, err os.Error) { + n := len(s) + if n < 2 { + return "", os.EINVAL + } + quote := s[0] + if quote != s[n-1] { + return "", os.EINVAL + } + s = s[1 : n-1] + + if quote == '`' { + if strings.Contains(s, "`") { + return "", os.EINVAL + } + return s, nil + } + if quote != '"' && quote != '\'' { + return "", os.EINVAL + } + + var buf bytes.Buffer + for len(s) > 0 { + c, multibyte, ss, err := UnquoteChar(s, quote) + if err != nil { + return "", err + } + s = ss + if c < utf8.RuneSelf || !multibyte { + buf.WriteByte(byte(c)) + } else { + buf.WriteString(string(c)) + } + if quote == '\'' && len(s) != 0 { + // single-quoted must be single character + return "", os.EINVAL + } + } + return buf.String(), nil +} diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go new file mode 100644 index 000000000..1235fcb9a --- /dev/null +++ b/libgo/go/strconv/quote_test.go @@ -0,0 +1,170 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "os" + . "strconv" + "testing" +) + +type quoteTest struct { + in string + out string +} + +var quotetests = []quoteTest{ + {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`}, + {"\\", `"\\"`}, + {"abc\xffdef", `"abc\xffdef"`}, + {"\u263a", `"\u263a"`}, + {"\U0010ffff", `"\U0010ffff"`}, + {"\x04", `"\x04"`}, +} + +func TestQuote(t *testing.T) { + for i := 0; i < len(quotetests); i++ { + tt := quotetests[i] + if out := Quote(tt.in); out != tt.out { + t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out) + } + } +} + +type canBackquoteTest struct { + in string + out bool +} + +var canbackquotetests = []canBackquoteTest{ + {"`", false}, + {string(0), false}, + {string(1), false}, + {string(2), false}, + {string(3), false}, + {string(4), false}, + {string(5), false}, + {string(6), false}, + {string(7), false}, + {string(8), false}, + {string(9), true}, // \t + {string(10), false}, + {string(11), false}, + {string(12), false}, + {string(13), false}, + {string(14), false}, + {string(15), false}, + {string(16), false}, + {string(17), false}, + {string(18), false}, + {string(19), false}, + {string(20), false}, + {string(21), false}, + {string(22), false}, + {string(23), false}, + {string(24), false}, + {string(25), false}, + {string(26), false}, + {string(27), false}, + {string(28), false}, + {string(29), false}, + {string(30), false}, + {string(31), false}, + {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true}, + {`0123456789`, true}, + {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true}, + {`abcdefghijklmnopqrstuvwxyz`, true}, + {`☺`, true}, +} + +func TestCanBackquote(t *testing.T) { + for i := 0; i < len(canbackquotetests); i++ { + tt := canbackquotetests[i] + if out := CanBackquote(tt.in); out != tt.out { + t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +var unquotetests = []quoteTest{ + {`""`, ""}, + {`"a"`, "a"}, + {`"abc"`, "abc"}, + {`"☺"`, "☺"}, + {`"hello world"`, "hello world"}, + {`"\xFF"`, "\xFF"}, + {`"\377"`, "\377"}, + {`"\u1234"`, "\u1234"}, + {`"\U00010111"`, "\U00010111"}, + {`"\U0001011111"`, "\U0001011111"}, + {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""}, + {`"'"`, "'"}, + + {`'a'`, "a"}, + {`'☹'`, "☹"}, + {`'\a'`, "\a"}, + {`'\x10'`, "\x10"}, + {`'\377'`, "\377"}, + {`'\u1234'`, "\u1234"}, + {`'\U00010111'`, "\U00010111"}, + {`'\t'`, "\t"}, + {`' '`, " "}, + {`'\''`, "'"}, + {`'"'`, "\""}, + + {"``", ``}, + {"`a`", `a`}, + {"`abc`", `abc`}, + {"`☺`", `☺`}, + {"`hello world`", `hello world`}, + {"`\\xFF`", `\xFF`}, + {"`\\377`", `\377`}, + {"`\\`", `\`}, + {"` `", ` `}, + {"` `", ` `}, +} + +var misquoted = []string{ + ``, + `"`, + `"a`, + `"'`, + `b"`, + `"\"`, + `'\'`, + `'ab'`, + `"\x1!"`, + `"\U12345678"`, + `"\z"`, + "`", + "`xxx", + "`\"", + `"\'"`, + `'\"'`, +} + +func TestUnquote(t *testing.T) { + for i := 0; i < len(unquotetests); i++ { + tt := unquotetests[i] + if out, err := Unquote(tt.in); err != nil && out != tt.out { + t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out) + } + } + + // run the quote tests too, backward + for i := 0; i < len(quotetests); i++ { + tt := quotetests[i] + if in, err := Unquote(tt.out); in != tt.in { + t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in) + } + } + + for i := 0; i < len(misquoted); i++ { + s := misquoted[i] + if out, err := Unquote(s); out != "" || err != os.EINVAL { + t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", os.EINVAL) + } + } +} diff --git a/libgo/go/strconv/testfp.txt b/libgo/go/strconv/testfp.txt new file mode 100644 index 000000000..08d3c4ef0 --- /dev/null +++ b/libgo/go/strconv/testfp.txt @@ -0,0 +1,181 @@ +# Floating-point conversion test cases. +# Empty lines and lines beginning with # are ignored. +# The rest have four fields per line: type, format, input, and output. +# The input is given either in decimal or binary scientific notation. +# The output is the string that should be produced by formatting the +# input with the given format. +# +# The formats are as in C's printf, except that %b means print +# binary scientific notation: NpE = N x 2^E. + +# TODO: +# Powers of 10. +# Powers of 2. +# %.20g versions. +# random sources +# random targets +# random targets ± half a ULP + +# Difficult boundary cases, derived from tables given in +# Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion +# ftp://ftp.ee.lbl.gov/testbase-report.ps.Z + +# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP +float64 %b 5e+125 6653062250012735p+365 +float64 %b 69e+267 4705683757438170p+841 +float64 %b 999e-026 6798841691080350p-129 +float64 %b 7861e-034 8975675289889240p-153 +float64 %b 75569e-254 6091718967192243p-880 +float64 %b 928609e-261 7849264900213743p-900 +float64 %b 9210917e+080 8341110837370930p+236 +float64 %b 84863171e+114 4625202867375927p+353 +float64 %b 653777767e+273 5068902999763073p+884 +float64 %b 5232604057e-298 5741343011915040p-1010 +float64 %b 27235667517e-109 6707124626673586p-380 +float64 %b 653532977297e-123 7078246407265384p-422 +float64 %b 3142213164987e-294 8219991337640559p-988 +float64 %b 46202199371337e-072 5224462102115359p-246 +float64 %b 231010996856685e-073 5224462102115359p-247 +float64 %b 9324754620109615e+212 5539753864394442p+705 +float64 %b 78459735791271921e+049 8388176519442766p+166 +float64 %b 272104041512242479e+200 5554409530847367p+670 +float64 %b 6802601037806061975e+198 5554409530847367p+668 +float64 %b 20505426358836677347e-221 4524032052079546p-722 +float64 %b 836168422905420598437e-234 5070963299887562p-760 +float64 %b 4891559871276714924261e+222 6452687840519111p+757 + +# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP +float64 %b 9e-265 8168427841980010p-930 +float64 %b 85e-037 6360455125664090p-169 +float64 %b 623e+100 6263531988747231p+289 +float64 %b 3571e+263 6234526311072170p+833 +float64 %b 81661e+153 6696636728760206p+472 +float64 %b 920657e-023 5975405561110124p-109 +float64 %b 4603285e-024 5975405561110124p-110 +float64 %b 87575437e-309 8452160731874668p-1053 +float64 %b 245540327e+122 4985336549131723p+381 +float64 %b 6138508175e+120 4985336549131723p+379 +float64 %b 83356057653e+193 5986732817132056p+625 +float64 %b 619534293513e+124 4798406992060657p+399 +float64 %b 2335141086879e+218 5419088166961646p+713 +float64 %b 36167929443327e-159 8135819834632444p-536 +float64 %b 609610927149051e-255 4576664294594737p-850 +float64 %b 3743626360493413e-165 6898586531774201p-549 +float64 %b 94080055902682397e-242 6273271706052298p-800 +float64 %b 899810892172646163e+283 7563892574477827p+947 +float64 %b 7120190517612959703e+120 5385467232557565p+409 +float64 %b 25188282901709339043e-252 5635662608542340p-825 +float64 %b 308984926168550152811e-052 5644774693823803p-157 +float64 %b 6372891218502368041059e+064 4616868614322430p+233 + +# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP +float64 %.0e 8511030020275656p-342 9e-88 +float64 %.1e 5201988407066741p-824 4.6e-233 +float64 %.2e 6406892948269899p+237 1.41e+87 +float64 %.3e 8431154198732492p+72 3.981e+37 +float64 %.4e 6475049196144587p+99 4.1040e+45 +float64 %.5e 8274307542972842p+726 2.92084e+234 +float64 %.6e 5381065484265332p-456 2.891946e-122 +float64 %.7e 6761728585499734p-1057 4.3787718e-303 +float64 %.8e 7976538478610756p+376 1.22770163e+129 +float64 %.9e 5982403858958067p+377 1.841552452e+129 +float64 %.10e 5536995190630837p+93 5.4835744350e+43 +float64 %.11e 7225450889282194p+710 3.89190181146e+229 +float64 %.12e 7225450889282194p+709 1.945950905732e+229 +float64 %.13e 8703372741147379p+117 1.4460958381605e+51 +float64 %.14e 8944262675275217p-1001 4.17367747458531e-286 +float64 %.15e 7459803696087692p-707 1.107950772878888e-197 +float64 %.16e 6080469016670379p-381 1.2345501366327440e-99 +float64 %.17e 8385515147034757p+721 9.25031711960365024e+232 +float64 %.18e 7514216811389786p-828 4.198047150284889840e-234 +float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88 +float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76 +float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127 + +# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP +float64 %.0e 6567258882077402p+952 3e+302 +float64 %.1e 6712731423444934p+535 7.6e+176 +float64 %.2e 6712731423444934p+534 3.78e+176 +float64 %.3e 5298405411573037p-957 4.350e-273 +float64 %.4e 5137311167659507p-144 2.3037e-28 +float64 %.5e 6722280709661868p+363 1.26301e+125 +float64 %.6e 5344436398034927p-169 7.142211e-36 +float64 %.7e 8369123604277281p-853 1.3934574e-241 +float64 %.8e 8995822108487663p-780 1.41463449e-219 +float64 %.9e 8942832835564782p-383 4.539277920e-100 +float64 %.10e 8942832835564782p-384 2.2696389598e-100 +float64 %.11e 8942832835564782p-385 1.13481947988e-100 +float64 %.12e 6965949469487146p-249 7.700366561890e-60 +float64 %.13e 6965949469487146p-250 3.8501832809448e-60 +float64 %.14e 6965949469487146p-251 1.92509164047238e-60 +float64 %.15e 7487252720986826p+548 6.898586531774201e+180 +float64 %.16e 5592117679628511p+164 1.3076622631878654e+65 +float64 %.17e 8887055249355788p+665 1.36052020756121240e+216 +float64 %.18e 6994187472632449p+690 3.592810217475959676e+223 +float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192 +float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97 +float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119 + +# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP +# NOTE: The lines with exponent p-149 have been changed from the +# paper. Those entries originally read p-150 and had a mantissa +# twice as large (and even), but IEEE single-precision has no p-150: +# that's the start of the denormals. +float32 %b 5e-20 15474250p-88 +float32 %b 67e+14 12479722p+29 +float32 %b 985e+15 14333636p+36 +# float32 %b 7693e-42 10979816p-150 +float32 %b 7693e-42 5489908p-149 +float32 %b 55895e-16 12888509p-61 +# float32 %b 996622e-44 14224264p-150 +float32 %b 996622e-44 7112132p-149 +float32 %b 7038531e-32 11420669p-107 +# float32 %b 60419369e-46 8623340p-150 +float32 %b 60419369e-46 4311670p-149 +float32 %b 702990899e-20 16209866p-61 +# float32 %b 6930161142e-48 9891056p-150 +float32 %b 6930161142e-48 4945528p-149 +float32 %b 25933168707e+13 14395800p+54 +float32 %b 596428896559e+20 12333860p+82 + +# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP +float32 %b 3e-23 9507380p-98 +float32 %b 57e+18 12960300p+42 +float32 %b 789e-35 10739312p-130 +float32 %b 2539e-18 11990089p-72 +float32 %b 76173e+28 9845130p+86 +float32 %b 887745e-11 9760860p-40 +float32 %b 5382571e-37 11447463p-124 +float32 %b 82381273e-35 8554961p-113 +float32 %b 750486563e-38 9975678p-120 +float32 %b 3752432815e-39 9975678p-121 +float32 %b 75224575729e-45 13105970p-137 +float32 %b 459926601011e+15 12466336p+65 + +# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP +float32 %.0e 12676506p-102 2e-24 +float32 %.1e 12676506p-103 1.2e-24 +float32 %.2e 15445013p+86 1.19e+33 +float32 %.3e 13734123p-138 3.941e-35 +float32 %.4e 12428269p-130 9.1308e-33 +float32 %.5e 15334037p-146 1.71900e-37 +float32 %.6e 11518287p-41 5.237910e-06 +float32 %.7e 12584953p-145 2.8216440e-37 +float32 %.8e 15961084p-125 3.75243281e-31 +float32 %.9e 14915817p-146 1.672120916e-37 +float32 %.10e 10845484p-102 2.1388945814e-24 +float32 %.11e 16431059p-61 7.12583594561e-12 + +# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP +float32 %.0e 16093626p+69 1e+28 +float32 %.1e 9983778p+25 3.4e+14 +float32 %.2e 12745034p+104 2.59e+38 +float32 %.3e 12706553p+72 6.001e+28 +float32 %.4e 11005028p+45 3.8721e+20 +float32 %.5e 15059547p+71 3.55584e+28 +float32 %.6e 16015691p-99 2.526831e-23 +float32 %.7e 8667859p+56 6.2458507e+23 +float32 %.8e 14855922p-82 3.07213267e-18 +float32 %.9e 14855922p-83 1.536066333e-18 +float32 %.10e 10144164p-110 7.8147796834e-27 +float32 %.11e 13248074p+95 5.24810279937e+35 |