diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-09-06 18:12:46 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-09-06 18:12:46 +0000 |
commit | aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch) | |
tree | 7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/strconv | |
parent | 920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff) | |
download | gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.zip gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.gz gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.bz2 |
libgo: update to Go 1.13beta1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/193497
From-SVN: r275473
Diffstat (limited to 'libgo/go/strconv')
-rw-r--r-- | libgo/go/strconv/atof.go | 230 | ||||
-rw-r--r-- | libgo/go/strconv/atof_test.go | 213 | ||||
-rw-r--r-- | libgo/go/strconv/atoi.go | 109 | ||||
-rw-r--r-- | libgo/go/strconv/atoi_test.go | 120 | ||||
-rw-r--r-- | libgo/go/strconv/example_test.go | 29 | ||||
-rw-r--r-- | libgo/go/strconv/extfloat.go | 15 | ||||
-rw-r--r-- | libgo/go/strconv/ftoa.go | 161 | ||||
-rw-r--r-- | libgo/go/strconv/ftoa_test.go | 31 | ||||
-rw-r--r-- | libgo/go/strconv/isprint.go | 94 | ||||
-rw-r--r-- | libgo/go/strconv/quote.go | 12 | ||||
-rw-r--r-- | libgo/go/strconv/strconv_test.go | 10 |
11 files changed, 874 insertions, 150 deletions
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go index fdcb8b3..eff1379 100644 --- a/libgo/go/strconv/atof.go +++ b/libgo/go/strconv/atof.go @@ -13,7 +13,7 @@ package strconv import "math" import "runtime" -var optimize = true // can change for testing +var optimize = true // set to false to force slow-path conversions for testing func equalIgnoreCase(s1, s2 string) bool { if len(s1) != len(s2) { @@ -84,6 +84,9 @@ func (b *decimal) set(s string) (ok bool) { sawdigits := false for ; i < len(s); i++ { switch { + case s[i] == '_': + // underscoreOK already called + continue case s[i] == '.': if sawdot { return @@ -120,7 +123,7 @@ func (b *decimal) set(s string) (ok bool) { // 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') { + if i < len(s) && lower(s[i]) == 'e' { i++ if i >= len(s) { return @@ -136,7 +139,11 @@ func (b *decimal) set(s string) (ok bool) { return } e := 0 - for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + // underscoreOK already called + continue + } if e < 10000 { e = e*10 + int(s[i]) - '0' } @@ -153,10 +160,9 @@ func (b *decimal) set(s string) (ok bool) { } // readFloat reads a decimal mantissa and exponent from a float -// string representation. It sets ok to false if the number could +// string representation. It returns ok==false if the number could // not fit return types or is invalid. -func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { - const uint64digits = 19 +func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) { i := 0 // optional sign @@ -172,6 +178,16 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { } // digits + base := uint64(10) + maxMantDigits := 19 // 10^19 fits in uint64 + expChar := byte('e') + if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' { + base = 16 + maxMantDigits = 16 // 16^16 fits in uint64 + i += 2 + expChar = 'p' + hex = true + } sawdot := false sawdigits := false nd := 0 @@ -179,6 +195,10 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { dp := 0 for ; i < len(s); i++ { switch c := s[i]; true { + case c == '_': + // underscoreOK already called + continue + case c == '.': if sawdot { return @@ -194,11 +214,23 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { continue } nd++ - if ndMant < uint64digits { - mantissa *= 10 + if ndMant < maxMantDigits { + mantissa *= base mantissa += uint64(c - '0') ndMant++ - } else if s[i] != '0' { + } else if c != '0' { + trunc = true + } + continue + + case base == 16 && 'a' <= lower(c) && lower(c) <= 'f': + sawdigits = true + nd++ + if ndMant < maxMantDigits { + mantissa *= 16 + mantissa += uint64(lower(c) - 'a' + 10) + ndMant++ + } else { trunc = true } continue @@ -212,12 +244,17 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { dp = nd } + if base == 16 { + dp *= 4 + ndMant *= 4 + } + // 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') { + if i < len(s) && lower(s[i]) == expChar { i++ if i >= len(s) { return @@ -233,12 +270,19 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { return } e := 0 - for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + // underscoreOK already called + continue + } if e < 10000 { e = e*10 + int(s[i]) - '0' } } dp += e * esign + } else if base == 16 { + // Must have exponent. + return } if i != len(s) { @@ -250,7 +294,6 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) { } ok = true return - } // decimal power of ten to binary power of two. @@ -439,6 +482,76 @@ func atof32exact(mantissa uint64, exp int, neg bool) (f float32, ok bool) { return } +// atofHex converts the hex floating-point string s +// to a rounded float32 or float64 value (depending on flt==&float32info or flt==&float64info) +// and returns it as a float64. +// The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative). +// If trunc is true, trailing non-zero bits have been omitted from the mantissa. +func atofHex(s string, flt *floatInfo, mantissa uint64, exp int, neg, trunc bool) (float64, error) { + maxExp := 1<<flt.expbits + flt.bias - 2 + minExp := flt.bias + 1 + exp += int(flt.mantbits) // mantissa now implicitly divided by 2^mantbits. + + // Shift mantissa and exponent to bring representation into float range. + // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits. + // For rounding, we need two more, where the bottom bit represents + // whether that bit or any later bit was non-zero. + // (If the mantissa has already lost non-zero bits, trunc is true, + // and we OR in a 1 below after shifting left appropriately.) + for mantissa != 0 && mantissa>>(flt.mantbits+2) == 0 { + mantissa <<= 1 + exp-- + } + if trunc { + mantissa |= 1 + } + for mantissa>>(1+flt.mantbits+2) != 0 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // If exponent is too negative, + // denormalize in hopes of making it representable. + // (The -2 is for the rounding bits.) + for mantissa > 1 && exp < minExp-2 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // Round using two bottom bits. + round := mantissa & 3 + mantissa >>= 2 + round |= mantissa & 1 // round to even (round up if mantissa is odd) + exp += 2 + if round == 3 { + mantissa++ + if mantissa == 1<<(1+flt.mantbits) { + mantissa >>= 1 + exp++ + } + } + + if mantissa>>flt.mantbits == 0 { // Denormal or zero. + exp = flt.bias + } + var err error + if exp > maxExp { // infinity and range error + mantissa = 1 << flt.mantbits + exp = maxExp + 1 + err = rangeError(fnParseFloat, s) + } + + bits := mantissa & (1<<flt.mantbits - 1) + bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits + if neg { + bits |= 1 << flt.mantbits << flt.expbits + } + if flt == &float32info { + return float64(math.Float32frombits(uint32(bits))), err + } + return math.Float64frombits(bits), err +} + const fnParseFloat = "ParseFloat" func atof32(s string) (f float32, err error) { @@ -446,28 +559,32 @@ func atof32(s string) (f float32, err error) { return float32(val), nil } - if optimize { - // Parse mantissa and exponent. - mantissa, exp, neg, trunc, ok := readFloat(s) - if ok { - // Try pure floating-point arithmetic conversion. - if !trunc { - if f, ok := atof32exact(mantissa, exp, neg); ok { - return f, nil - } + mantissa, exp, neg, trunc, hex, ok := readFloat(s) + if hex && ok { + f, err := atofHex(s, &float32info, mantissa, exp, neg, trunc) + return float32(f), err + } + + if optimize && ok { + // Try pure floating-point arithmetic conversion. + if !trunc { + if f, ok := atof32exact(mantissa, exp, neg); ok { + return f, nil } - // Try another fast path. - ext := new(extFloat) - if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float32info); ok { - b, ovf := ext.floatBits(&float32info) - f = math.Float32frombits(uint32(b)) - if ovf { - err = rangeError(fnParseFloat, s) - } - return f, err + } + // Try another fast path. + ext := new(extFloat) + if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float32info); ok { + b, ovf := ext.floatBits(&float32info) + f = math.Float32frombits(uint32(b)) + if ovf { + err = rangeError(fnParseFloat, s) } + return f, err } } + + // Slow fallback. var d decimal if !d.set(s) { return 0, syntaxError(fnParseFloat, s) @@ -485,28 +602,31 @@ func atof64(s string) (f float64, err error) { return val, nil } - if optimize { - // Parse mantissa and exponent. - mantissa, exp, neg, trunc, ok := readFloat(s) - if ok { - // Try pure floating-point arithmetic conversion. - if !trunc { - if f, ok := atof64exact(mantissa, exp, neg); ok { - return f, nil - } + mantissa, exp, neg, trunc, hex, ok := readFloat(s) + if hex && ok { + return atofHex(s, &float64info, mantissa, exp, neg, trunc) + } + + if optimize && ok { + // Try pure floating-point arithmetic conversion. + if !trunc { + if f, ok := atof64exact(mantissa, exp, neg); ok { + return f, nil } - // Try another fast path. - ext := new(extFloat) - if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float64info); ok { - b, ovf := ext.floatBits(&float64info) - f = math.Float64frombits(b) - if ovf { - err = rangeError(fnParseFloat, s) - } - return f, err + } + // Try another fast path. + ext := new(extFloat) + if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float64info); ok { + b, ovf := ext.floatBits(&float64info) + f = math.Float64frombits(b) + if ovf { + err = rangeError(fnParseFloat, s) } + return f, err } } + + // Slow fallback. var d decimal if !d.set(s) { return 0, syntaxError(fnParseFloat, s) @@ -524,9 +644,13 @@ func atof64(s string) (f float64, err error) { // When bitSize=32, the result still has type float64, but it will be // convertible to float32 without changing its value. // -// If s is well-formed and near a valid floating point number, -// ParseFloat returns the nearest floating point number rounded +// ParseFloat accepts decimal and hexadecimal floating-point number syntax. +// If s is well-formed and near a valid floating-point number, +// ParseFloat returns the nearest floating-point number rounded // using IEEE754 unbiased rounding. +// (Parsing a hexadecimal floating-point value only rounds when +// there are more bits in the hexadecimal representatiton than +// will fit in the mantissa.) // // The errors that ParseFloat returns have concrete type *NumError // and include err.Num = s. @@ -536,7 +660,13 @@ func atof64(s string) (f float64, err error) { // If s is syntactically well-formed but is more than 1/2 ULP // away from the largest floating point number of the given size, // ParseFloat returns f = ±Inf, err.Err = ErrRange. +// +// ParseFloat recognizes the strings "NaN", "+Inf", and "-Inf" as their +// respective special floating point values. It ignores case when matching. func ParseFloat(s string, bitSize int) (float64, error) { + if !underscoreOK(s) { + return 0, syntaxError(fnParseFloat, s) + } if bitSize == 32 { f, err := atof32(s) return float64(f), err diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go index cf4d47c..abe6c64 100644 --- a/libgo/go/strconv/atof_test.go +++ b/libgo/go/strconv/atof_test.go @@ -43,6 +43,23 @@ var atoftests = []atofTest{ {"1e-20", "1e-20", nil}, {"625e-3", "0.625", nil}, + // Hexadecimal floating-point. + {"0x1p0", "1", nil}, + {"0x1p1", "2", nil}, + {"0x1p-1", "0.5", nil}, + {"0x1ep-1", "15", nil}, + {"-0x1ep-1", "-15", nil}, + {"-0x1_ep-1", "-15", nil}, + {"0x1p-200", "6.223015277861142e-61", nil}, + {"0x1p200", "1.6069380442589903e+60", nil}, + {"0x1fFe2.p0", "131042", nil}, + {"0x1fFe2.P0", "131042", nil}, + {"-0x2p3", "-16", nil}, + {"0x0.fp4", "15", nil}, + {"0x0.fp0", "0.9375", nil}, + {"0x1e2", "0", ErrSyntax}, + {"1p2", "0", ErrSyntax}, + // zeros {"0", "0", nil}, {"0e0", "0", nil}, @@ -58,6 +75,11 @@ var atoftests = []atofTest{ {"0.00e-01234567890123456789", "0", nil}, {"-0e+01234567890123456789", "-0", nil}, {"-0.00e-01234567890123456789", "-0", nil}, + {"0x0p+01234567890123456789", "0", nil}, + {"0x0.00p-01234567890123456789", "0", nil}, + {"-0x0p+01234567890123456789", "-0", nil}, + {"-0x0.00p-01234567890123456789", "-0", nil}, + {"0e291", "0", nil}, // issue 15364 {"0e292", "0", nil}, // issue 15364 {"0e347", "0", nil}, // issue 15364 @@ -66,6 +88,26 @@ var atoftests = []atofTest{ {"-0e292", "-0", nil}, {"-0e347", "-0", nil}, {"-0e348", "-0", nil}, + {"0x0p126", "0", nil}, + {"0x0p127", "0", nil}, + {"0x0p128", "0", nil}, + {"0x0p129", "0", nil}, + {"0x0p130", "0", nil}, + {"0x0p1022", "0", nil}, + {"0x0p1023", "0", nil}, + {"0x0p1024", "0", nil}, + {"0x0p1025", "0", nil}, + {"0x0p1026", "0", nil}, + {"-0x0p126", "-0", nil}, + {"-0x0p127", "-0", nil}, + {"-0x0p128", "-0", nil}, + {"-0x0p129", "-0", nil}, + {"-0x0p130", "-0", nil}, + {"-0x0p1022", "-0", nil}, + {"-0x0p1023", "-0", nil}, + {"-0x0p1024", "-0", nil}, + {"-0x0p1025", "-0", nil}, + {"-0x0p1026", "-0", nil}, // NaNs {"nan", "NaN", nil}, @@ -83,21 +125,46 @@ var atoftests = []atofTest{ // largest float64 {"1.7976931348623157e308", "1.7976931348623157e+308", nil}, {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil}, + {"0x1.fffffffffffffp1023", "1.7976931348623157e+308", nil}, + {"-0x1.fffffffffffffp1023", "-1.7976931348623157e+308", nil}, + {"0x1fffffffffffffp+971", "1.7976931348623157e+308", nil}, + {"-0x1fffffffffffffp+971", "-1.7976931348623157e+308", nil}, + {"0x.1fffffffffffffp1027", "1.7976931348623157e+308", nil}, + {"-0x.1fffffffffffffp1027", "-1.7976931348623157e+308", nil}, + // next float64 - too large {"1.7976931348623159e308", "+Inf", ErrRange}, {"-1.7976931348623159e308", "-Inf", ErrRange}, + {"0x1p1024", "+Inf", ErrRange}, + {"-0x1p1024", "-Inf", ErrRange}, + {"0x2p1023", "+Inf", ErrRange}, + {"-0x2p1023", "-Inf", ErrRange}, + {"0x.1p1028", "+Inf", ErrRange}, + {"-0x.1p1028", "-Inf", ErrRange}, + {"0x.2p1027", "+Inf", ErrRange}, + {"-0x.2p1027", "-Inf", ErrRange}, + // the border is ...158079 // borderline - okay {"1.7976931348623158e308", "1.7976931348623157e+308", nil}, {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil}, + {"0x1.fffffffffffff7fffp1023", "1.7976931348623157e+308", nil}, + {"-0x1.fffffffffffff7fffp1023", "-1.7976931348623157e+308", nil}, // borderline - too large {"1.797693134862315808e308", "+Inf", ErrRange}, {"-1.797693134862315808e308", "-Inf", ErrRange}, + {"0x1.fffffffffffff8p1023", "+Inf", ErrRange}, + {"-0x1.fffffffffffff8p1023", "-Inf", ErrRange}, + {"0x1fffffffffffff.8p+971", "+Inf", ErrRange}, + {"-0x1fffffffffffff8p+967", "-Inf", ErrRange}, + {"0x.1fffffffffffff8p1027", "+Inf", ErrRange}, + {"-0x.1fffffffffffff9p1027", "-Inf", ErrRange}, // a little too large {"1e308", "1e+308", nil}, {"2e308", "+Inf", ErrRange}, {"1e309", "+Inf", ErrRange}, + {"0x1p1025", "+Inf", ErrRange}, // way too large {"1e310", "+Inf", ErrRange}, @@ -106,6 +173,12 @@ var atoftests = []atofTest{ {"-1e400", "-Inf", ErrRange}, {"1e400000", "+Inf", ErrRange}, {"-1e400000", "-Inf", ErrRange}, + {"0x1p1030", "+Inf", ErrRange}, + {"0x1p2000", "+Inf", ErrRange}, + {"0x1p2000000000", "+Inf", ErrRange}, + {"-0x1p1030", "-Inf", ErrRange}, + {"-0x1p2000", "-Inf", ErrRange}, + {"-0x1p2000000000", "-Inf", ErrRange}, // denormalized {"1e-305", "1e-305", nil}, @@ -125,17 +198,75 @@ var atoftests = []atofTest{ {"1e-350", "0", nil}, {"1e-400000", "0", nil}, + // Near denormals and denormals. + {"0x2.00000000000000p-1010", "1.8227805048890994e-304", nil}, // 0x00e0000000000000 + {"0x1.fffffffffffff0p-1010", "1.8227805048890992e-304", nil}, // 0x00dfffffffffffff + {"0x1.fffffffffffff7p-1010", "1.8227805048890992e-304", nil}, // rounded down + {"0x1.fffffffffffff8p-1010", "1.8227805048890994e-304", nil}, // rounded up + {"0x1.fffffffffffff9p-1010", "1.8227805048890994e-304", nil}, // rounded up + + {"0x2.00000000000000p-1022", "4.450147717014403e-308", nil}, // 0x0020000000000000 + {"0x1.fffffffffffff0p-1022", "4.4501477170144023e-308", nil}, // 0x001fffffffffffff + {"0x1.fffffffffffff7p-1022", "4.4501477170144023e-308", nil}, // rounded down + {"0x1.fffffffffffff8p-1022", "4.450147717014403e-308", nil}, // rounded up + {"0x1.fffffffffffff9p-1022", "4.450147717014403e-308", nil}, // rounded up + + {"0x1.00000000000000p-1022", "2.2250738585072014e-308", nil}, // 0x0010000000000000 + {"0x0.fffffffffffff0p-1022", "2.225073858507201e-308", nil}, // 0x000fffffffffffff + {"0x0.ffffffffffffe0p-1022", "2.2250738585072004e-308", nil}, // 0x000ffffffffffffe + {"0x0.ffffffffffffe7p-1022", "2.2250738585072004e-308", nil}, // rounded down + {"0x1.ffffffffffffe8p-1023", "2.225073858507201e-308", nil}, // rounded up + {"0x1.ffffffffffffe9p-1023", "2.225073858507201e-308", nil}, // rounded up + + {"0x0.00000003fffff0p-1022", "2.072261e-317", nil}, // 0x00000000003fffff + {"0x0.00000003456780p-1022", "1.694649e-317", nil}, // 0x0000000000345678 + {"0x0.00000003456787p-1022", "1.694649e-317", nil}, // rounded down + {"0x0.00000003456788p-1022", "1.694649e-317", nil}, // rounded down (half to even) + {"0x0.00000003456790p-1022", "1.6946496e-317", nil}, // 0x0000000000345679 + {"0x0.00000003456789p-1022", "1.6946496e-317", nil}, // rounded up + + {"0x0.0000000345678800000000000000000000000001p-1022", "1.6946496e-317", nil}, // rounded up + + {"0x0.000000000000f0p-1022", "7.4e-323", nil}, // 0x000000000000000f + {"0x0.00000000000060p-1022", "3e-323", nil}, // 0x0000000000000006 + {"0x0.00000000000058p-1022", "3e-323", nil}, // rounded up + {"0x0.00000000000057p-1022", "2.5e-323", nil}, // rounded down + {"0x0.00000000000050p-1022", "2.5e-323", nil}, // 0x0000000000000005 + + {"0x0.00000000000010p-1022", "5e-324", nil}, // 0x0000000000000001 + {"0x0.000000000000081p-1022", "5e-324", nil}, // rounded up + {"0x0.00000000000008p-1022", "0", nil}, // rounded down + {"0x0.00000000000007fp-1022", "0", nil}, // rounded down + // try to overflow exponent {"1e-4294967296", "0", nil}, {"1e+4294967296", "+Inf", ErrRange}, {"1e-18446744073709551616", "0", nil}, {"1e+18446744073709551616", "+Inf", ErrRange}, + {"0x1p-4294967296", "0", nil}, + {"0x1p+4294967296", "+Inf", ErrRange}, + {"0x1p-18446744073709551616", "0", nil}, + {"0x1p+18446744073709551616", "+Inf", ErrRange}, // Parse errors {"1e", "0", ErrSyntax}, {"1e-", "0", ErrSyntax}, {".e-1", "0", ErrSyntax}, {"1\x00.2", "0", ErrSyntax}, + {"0x", "0", ErrSyntax}, + {"0x.", "0", ErrSyntax}, + {"0x1", "0", ErrSyntax}, + {"0x.1", "0", ErrSyntax}, + {"0x1p", "0", ErrSyntax}, + {"0x.1p", "0", ErrSyntax}, + {"0x1p+", "0", ErrSyntax}, + {"0x.1p+", "0", ErrSyntax}, + {"0x1p-", "0", ErrSyntax}, + {"0x.1p-", "0", ErrSyntax}, + {"0x1p+2", "4", nil}, + {"0x.1p+2", "0.25", nil}, + {"0x1p-2", "0.25", nil}, + {"0x.1p-2", "0.015625", nil}, // https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ {"2.2250738585072012e-308", "2.2250738585072014e-308", nil}, @@ -148,42 +279,109 @@ var atoftests = []atofTest{ // A different kind of very large number. {"22.222222222222222", "22.22222222222222", nil}, {"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil}, + {"0x1.1111111111111p222", "7.18931911124017e+66", nil}, + {"0x2.2222222222222p221", "7.18931911124017e+66", nil}, + {"0x2." + strings.Repeat("2", 4000) + "p221", "7.18931911124017e+66", nil}, // Exactly halfway between 1 and math.Nextafter(1, 2). // Round to even (down). {"1.00000000000000011102230246251565404236316680908203125", "1", nil}, + {"0x1.00000000000008p0", "1", nil}, // Slightly lower; still round down. {"1.00000000000000011102230246251565404236316680908203124", "1", nil}, + {"0x1.00000000000007Fp0", "1", nil}, // Slightly higher; round up. {"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil}, + {"0x1.000000000000081p0", "1.0000000000000002", nil}, + {"0x1.00000000000009p0", "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}, + {"0x1.00000000000008" + strings.Repeat("0", 10000) + "1p0", "1.0000000000000002", nil}, + + // Halfway between x := math.Nextafter(1, 2) and math.Nextafter(x, 2) + // Round to even (up). + {"1.00000000000000033306690738754696212708950042724609375", "1.0000000000000004", nil}, + {"0x1.00000000000018p0", "1.0000000000000004", nil}, + + // Underscores. + {"1_23.50_0_0e+1_2", "1.235e+14", nil}, + {"-_123.5e+12", "0", ErrSyntax}, + {"+_123.5e+12", "0", ErrSyntax}, + {"_123.5e+12", "0", ErrSyntax}, + {"1__23.5e+12", "0", ErrSyntax}, + {"123_.5e+12", "0", ErrSyntax}, + {"123._5e+12", "0", ErrSyntax}, + {"123.5_e+12", "0", ErrSyntax}, + {"123.5__0e+12", "0", ErrSyntax}, + {"123.5e_+12", "0", ErrSyntax}, + {"123.5e+_12", "0", ErrSyntax}, + {"123.5e_-12", "0", ErrSyntax}, + {"123.5e-_12", "0", ErrSyntax}, + {"123.5e+1__2", "0", ErrSyntax}, + {"123.5e+12_", "0", ErrSyntax}, + + {"0x_1_2.3_4_5p+1_2", "74565", nil}, + {"-_0x12.345p+12", "0", ErrSyntax}, + {"+_0x12.345p+12", "0", ErrSyntax}, + {"_0x12.345p+12", "0", ErrSyntax}, + {"0x__12.345p+12", "0", ErrSyntax}, + {"0x1__2.345p+12", "0", ErrSyntax}, + {"0x12_.345p+12", "0", ErrSyntax}, + {"0x12._345p+12", "0", ErrSyntax}, + {"0x12.3__45p+12", "0", ErrSyntax}, + {"0x12.345_p+12", "0", ErrSyntax}, + {"0x12.345p_+12", "0", ErrSyntax}, + {"0x12.345p+_12", "0", ErrSyntax}, + {"0x12.345p_-12", "0", ErrSyntax}, + {"0x12.345p-_12", "0", ErrSyntax}, + {"0x12.345p+1__2", "0", ErrSyntax}, + {"0x12.345p+12_", "0", ErrSyntax}, } var atof32tests = []atofTest{ + // Hex + {"0x1p-100", "7.888609e-31", nil}, + {"0x1p100", "1.2676506e+30", nil}, + // Exactly halfway between 1 and the next float32. // Round to even (down). {"1.000000059604644775390625", "1", nil}, + {"0x1.000001p0", "1", nil}, // Slightly lower. {"1.000000059604644775390624", "1", nil}, + {"0x1.0000008p0", "1", nil}, + {"0x1.000000fp0", "1", nil}, // Slightly higher. {"1.000000059604644775390626", "1.0000001", nil}, + {"0x1.000002p0", "1.0000001", nil}, + {"0x1.0000018p0", "1.0000001", nil}, + {"0x1.0000011p0", "1.0000001", nil}, // Slightly higher, but you have to read all the way to the end. {"1.000000059604644775390625" + strings.Repeat("0", 10000) + "1", "1.0000001", nil}, + {"0x1.000001" + strings.Repeat("0", 10000) + "1p0", "1.0000001", nil}, // largest float32: (1<<128) * (1 - 2^-24) {"340282346638528859811704183484516925440", "3.4028235e+38", nil}, {"-340282346638528859811704183484516925440", "-3.4028235e+38", nil}, + {"0x.ffffffp128", "3.4028235e+38", nil}, + {"-340282346638528859811704183484516925440", "-3.4028235e+38", nil}, + {"-0x.ffffffp128", "-3.4028235e+38", nil}, // next float32 - too large {"3.4028236e38", "+Inf", ErrRange}, {"-3.4028236e38", "-Inf", ErrRange}, + {"0x1.0p128", "+Inf", ErrRange}, + {"-0x1.0p128", "-Inf", ErrRange}, // the border is 3.40282356779...e+38 // borderline - okay {"3.402823567e38", "3.4028235e+38", nil}, {"-3.402823567e38", "-3.4028235e+38", nil}, + {"0x.ffffff7fp128", "3.4028235e+38", nil}, + {"-0x.ffffff7fp128", "-3.4028235e+38", nil}, // borderline - too large {"3.4028235678e38", "+Inf", ErrRange}, {"-3.4028235678e38", "-Inf", ErrRange}, + {"0x.ffffff8p128", "+Inf", ErrRange}, + {"-0x.ffffff8p128", "-Inf", ErrRange}, // Denormals: less than 2^-126 {"1e-38", "1e-38", nil}, @@ -195,9 +393,24 @@ var atof32tests = []atofTest{ {"1e-44", "1e-44", nil}, {"6e-45", "6e-45", nil}, // 4p-149 = 5.6e-45 {"5e-45", "6e-45", nil}, + // Smallest denormal {"1e-45", "1e-45", nil}, // 1p-149 = 1.4e-45 {"2e-45", "1e-45", nil}, + {"3e-45", "3e-45", nil}, + + // Near denormals and denormals. + {"0x0.89aBcDp-125", "1.2643093e-38", nil}, // 0x0089abcd + {"0x0.8000000p-125", "1.1754944e-38", nil}, // 0x00800000 + {"0x0.1234560p-125", "1.671814e-39", nil}, // 0x00123456 + {"0x0.1234567p-125", "1.671814e-39", nil}, // rounded down + {"0x0.1234568p-125", "1.671814e-39", nil}, // rounded down + {"0x0.1234569p-125", "1.671815e-39", nil}, // rounded up + {"0x0.1234570p-125", "1.671815e-39", nil}, // 0x00123457 + {"0x0.0000010p-125", "1e-45", nil}, // 0x00000001 + {"0x0.00000081p-125", "1e-45", nil}, // rounded up + {"0x0.0000008p-125", "0", nil}, // rounded down + {"0x0.0000007p-125", "0", nil}, // rounded down // 2^92 = 8388608p+69 = 4951760157141521099596496896 (4.9517602e27) // is an exact power of two that needs 8 decimal digits to be correctly diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go index ff33d55..31774d0 100644 --- a/libgo/go/strconv/atoi.go +++ b/libgo/go/strconv/atoi.go @@ -6,6 +6,14 @@ package strconv import "errors" +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} + // ErrRange indicates that a value is out of range for the target type. var ErrRange = errors.New("value out of range") @@ -50,10 +58,12 @@ const maxUint64 = 1<<64 - 1 func ParseUint(s string, base int, bitSize int) (uint64, error) { const fnParseUint = "ParseUint" - if len(s) == 0 { + if s == "" || !underscoreOK(s) { return 0, syntaxError(fnParseUint, s) } + base0 := base == 0 + s0 := s switch { case 2 <= base && base <= 36: @@ -61,18 +71,22 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { case base == 0: // Look for octal, hex prefix. - switch { - case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): - if len(s) < 3 { - return 0, syntaxError(fnParseUint, s0) + base = 10 + if s[0] == '0' { + switch { + case len(s) >= 3 && lower(s[1]) == 'b': + base = 2 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'o': + base = 8 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'x': + base = 16 + s = s[2:] + default: + base = 8 + s = s[1:] } - base = 16 - s = s[2:] - case s[0] == '0': - base = 8 - s = s[1:] - default: - base = 10 } default: @@ -103,12 +117,13 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { for _, c := range []byte(s) { var d byte switch { + case c == '_' && base0: + // underscoreOK already called + continue case '0' <= c && c <= '9': d = c - '0' - case 'a' <= c && c <= 'z': - d = c - 'a' + 10 - case 'A' <= c && c <= 'Z': - d = c - 'A' + 10 + case 'a' <= lower(c) && lower(c) <= 'z': + d = lower(c) - 'a' + 10 default: return 0, syntaxError(fnParseUint, s0) } @@ -138,13 +153,14 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { // bit size (0 to 64) and returns the corresponding value i. // // If base == 0, the base is implied by the string's prefix: -// base 16 for "0x", base 8 for "0", and base 10 otherwise. -// For bases 1, below 0 or above 36 an error is returned. +// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x", +// and base 10 otherwise. +// If base is below 0, is 1, or is above 36, an error is returned. // // The bitSize argument specifies the integer type // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 // correspond to int, int8, int16, int32, and int64. -// For a bitSize below 0 or above 64 an error is returned. +// If bitSize is below 0 or above 64, an error is returned. // // The errors that ParseInt returns have concrete type *NumError // and include err.Num = s. If s is empty or contains invalid @@ -156,8 +172,7 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { func ParseInt(s string, base int, bitSize int) (i int64, err error) { const fnParseInt = "ParseInt" - // Empty string bad. - if len(s) == 0 { + if s == "" { return 0, syntaxError(fnParseInt, s) } @@ -228,10 +243,60 @@ func Atoi(s string) (int, error) { return n, nil } - // Slow path for invalid or big integers. + // Slow path for invalid, big, or underscored integers. i64, err := ParseInt(s, 10, 0) if nerr, ok := err.(*NumError); ok { nerr.Func = fnAtoi } return int(i64), err } + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + hex := false + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + hex = lower(s[1]) == 'x' + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Underscore must also be followed by digit. + if saw == '_' { + return false + } + // Saw non-digit, non-underscore. + saw = '!' + } + return saw != '_' +} diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go index e2f505a..b167c96 100644 --- a/libgo/go/strconv/atoi_test.go +++ b/libgo/go/strconv/atoi_test.go @@ -29,6 +29,10 @@ var parseUint64Tests = []parseUint64Test{ {"18446744073709551615", 1<<64 - 1, nil}, {"18446744073709551616", 1<<64 - 1, ErrRange}, {"18446744073709551620", 1<<64 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, } type parseUint64BaseTest struct { @@ -61,6 +65,69 @@ var parseUint64BaseTests = []parseUint64BaseTest{ {"01777777777777777777778", 0, 0, ErrSyntax}, {"02000000000000000000000", 0, 1<<64 - 1, ErrRange}, {"0200000000000000000000", 0, 1 << 61, nil}, + {"0b", 0, 0, ErrSyntax}, + {"0B", 0, 0, ErrSyntax}, + {"0b101", 0, 5, nil}, + {"0B101", 0, 5, nil}, + {"0o", 0, 0, ErrSyntax}, + {"0O", 0, 0, ErrSyntax}, + {"0o377", 0, 255, nil}, + {"0O377", 0, 255, nil}, + + // underscores allowed with base == 0 only + {"1_2_3_4_5", 0, 12345, nil}, // base 0 => 10 + {"_12345", 0, 0, ErrSyntax}, + {"1__2345", 0, 0, ErrSyntax}, + {"12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 10, 0, ErrSyntax}, // base 10 + {"_12345", 10, 0, ErrSyntax}, + {"1__2345", 10, 0, ErrSyntax}, + {"12345_", 10, 0, ErrSyntax}, + + {"0x_1_2_3_4_5", 0, 0x12345, nil}, // base 0 => 16 + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 16, 0, ErrSyntax}, // base 16 + {"_12345", 16, 0, ErrSyntax}, + {"1__2345", 16, 0, ErrSyntax}, + {"1234__5", 16, 0, ErrSyntax}, + {"12345_", 16, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0377) + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, + + {"0o_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0o377) + {"_0o12345", 0, 0, ErrSyntax}, + {"0o__12345", 0, 0, ErrSyntax}, + {"0o1234__5", 0, 0, ErrSyntax}, + {"0o12345_", 0, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 8, 0, ErrSyntax}, // base 8 + {"_012345", 8, 0, ErrSyntax}, + {"0__12345", 8, 0, ErrSyntax}, + {"01234__5", 8, 0, ErrSyntax}, + {"012345_", 8, 0, ErrSyntax}, + + {"0b_1_0_1", 0, 5, nil}, // base 0 => 2 (0b101) + {"_0b101", 0, 0, ErrSyntax}, + {"0b__101", 0, 0, ErrSyntax}, + {"0b1__01", 0, 0, ErrSyntax}, + {"0b10__1", 0, 0, ErrSyntax}, + {"0b101_", 0, 0, ErrSyntax}, + + {"1_0_1", 2, 0, ErrSyntax}, // base 2 + {"_101", 2, 0, ErrSyntax}, + {"1_01", 2, 0, ErrSyntax}, + {"10_1", 2, 0, ErrSyntax}, + {"101_", 2, 0, ErrSyntax}, } type parseInt64Test struct { @@ -87,6 +154,11 @@ var parseInt64Tests = []parseInt64Test{ {"-9223372036854775808", -1 << 63, nil}, {"9223372036854775809", 1<<63 - 1, ErrRange}, {"-9223372036854775809", -1 << 63, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, } type parseInt64BaseTest struct { @@ -144,6 +216,26 @@ var parseInt64BaseTests = []parseInt64BaseTest{ {"10", 16, 16, nil}, {"-123456789abcdef", 16, -0x123456789abcdef, nil}, {"7fffffffffffffff", 16, 1<<63 - 1, nil}, + + // underscores + {"-0x_1_2_3_4_5", 0, -0x12345, nil}, + {"0x_1_2_3_4_5", 0, 0x12345, nil}, + {"-_0x12345", 0, 0, ErrSyntax}, + {"_-0x12345", 0, 0, ErrSyntax}, + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"-0_1_2_3_4_5", 0, -012345, nil}, // octal + {"0_1_2_3_4_5", 0, 012345, nil}, // octal + {"-_012345", 0, 0, ErrSyntax}, + {"_-012345", 0, 0, ErrSyntax}, + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, } type parseUint32Test struct { @@ -162,6 +254,11 @@ var parseUint32Tests = []parseUint32Test{ {"987654321", 987654321, nil}, {"4294967295", 1<<32 - 1, nil}, {"4294967296", 1<<32 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, } type parseInt32Test struct { @@ -190,6 +287,11 @@ var parseInt32Tests = []parseInt32Test{ {"-2147483648", -1 << 31, nil}, {"2147483649", 1<<31 - 1, ErrRange}, {"-2147483649", -1 << 31, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, } type numErrorTest struct { @@ -419,12 +521,22 @@ var parseBaseTests = []parseErrorTest{ {37, baseErrStub}, } +func equalError(a, b error) bool { + if a == nil { + return b == nil + } + if b == nil { + return a == nil + } + return a.Error() == b.Error() +} + func TestParseIntBitSize(t *testing.T) { for i := range parseBitSizeTests { test := &parseBitSizeTests[i] testErr := test.errStub("ParseInt", test.arg) _, err := ParseInt("0", 0, test.arg) - if !reflect.DeepEqual(testErr, err) { + if !equalError(testErr, err) { t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v", test.arg, err, testErr) } @@ -436,7 +548,7 @@ func TestParseUintBitSize(t *testing.T) { test := &parseBitSizeTests[i] testErr := test.errStub("ParseUint", test.arg) _, err := ParseUint("0", 0, test.arg) - if !reflect.DeepEqual(testErr, err) { + if !equalError(testErr, err) { t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v", test.arg, err, testErr) } @@ -448,7 +560,7 @@ func TestParseIntBase(t *testing.T) { test := &parseBaseTests[i] testErr := test.errStub("ParseInt", test.arg) _, err := ParseInt("0", test.arg, 0) - if !reflect.DeepEqual(testErr, err) { + if !equalError(testErr, err) { t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v", test.arg, err, testErr) } @@ -460,7 +572,7 @@ func TestParseUintBase(t *testing.T) { test := &parseBaseTests[i] testErr := test.errStub("ParseUint", test.arg) _, err := ParseUint("0", test.arg, 0) - if !reflect.DeepEqual(testErr, err) { + if !equalError(testErr, err) { t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v", test.arg, err, testErr) } diff --git a/libgo/go/strconv/example_test.go b/libgo/go/strconv/example_test.go index 2d1a2a9..50f6b20 100644 --- a/libgo/go/strconv/example_test.go +++ b/libgo/go/strconv/example_test.go @@ -222,10 +222,39 @@ func ExampleParseFloat() { if s, err := strconv.ParseFloat(v, 64); err == nil { fmt.Printf("%T, %v\n", s, s) } + if s, err := strconv.ParseFloat("NaN", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + // ParseFloat is case insensitive + if s, err := strconv.ParseFloat("nan", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } // Output: // float64, 3.1415927410125732 // float64, 3.1415926535 + // float64, NaN + // float64, NaN + // float64, +Inf + // float64, +Inf + // float64, -Inf + // float64, -0 + // float64, 0 } func ExampleParseInt() { diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go index 32d3340..2a2dd7a 100644 --- a/libgo/go/strconv/extfloat.go +++ b/libgo/go/strconv/extfloat.go @@ -214,20 +214,9 @@ func (f *extFloat) Normalize() uint { // Multiply sets f to the product f*g: the result is correctly rounded, // but not normalized. func (f *extFloat) Multiply(g extFloat) { - fhi, flo := f.mant>>32, uint64(uint32(f.mant)) - ghi, glo := g.mant>>32, uint64(uint32(g.mant)) - - // Cross products. - cross1 := fhi * glo - cross2 := flo * ghi - - // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo - f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32) - rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32) + hi, lo := bits.Mul64(f.mant, g.mant) // Round up. - rem += (1 << 31) - - f.mant += (rem >> 32) + f.mant = hi + (lo >> 63) f.exp = f.exp + g.exp + 64 } diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go index a7ccbe6..8ce6ef3 100644 --- a/libgo/go/strconv/ftoa.go +++ b/libgo/go/strconv/ftoa.go @@ -32,12 +32,14 @@ var float64info = floatInfo{52, 11, -1023} // '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). +// 'g' ('e' for large exponents, 'f' otherwise), +// 'G' ('E' for large exponents, 'f' otherwise), +// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or +// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent). // // 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. +// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats. +// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point. // For 'g' and 'G' it is the maximum number of significant digits (trailing // zeros are removed). // The special precision -1 uses the smallest number of digits @@ -94,10 +96,13 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte { } exp += flt.bias - // Pick off easy binary format. + // Pick off easy binary, hex formats. if fmt == 'b' { return fmtB(dst, neg, mant, exp, flt) } + if fmt == 'x' || fmt == 'X' { + return fmtX(dst, prec, fmt, neg, mant, exp, flt) + } if !optimize { return bigFtoa(dst, prec, fmt, neg, mant, exp, flt) @@ -284,39 +289,80 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { // would round to the original mantissa and not the neighbors. inclusive := mant%2 == 0 + // As we walk the digits we want to know whether rounding up would fall + // within the upper bound. This is tracked by upperdelta: + // + // If upperdelta == 0, the digits of d and upper are the same so far. + // + // If upperdelta == 1, we saw a difference of 1 between d and upper on a + // previous digit and subsequently only 9s for d and 0s for upper. + // (Thus rounding up may fall outside the bound, if it is exclusive.) + // + // If upperdelta == 2, then the difference is greater than 1 + // and we know that rounding up falls within the bound. + var upperdelta uint8 + // 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++ { + for ui := 0; ; ui++ { + // lower, d, and upper may have the decimal points at different + // places. In this case upper is the longest, so we iterate from + // ui==0 and start li and mi at (possibly) -1. + mi := ui - upper.dp + d.dp + if mi >= d.nd { + break + } + li := ui - upper.dp + lower.dp l := byte('0') // lower digit - if i < lower.nd { - l = lower.d[i] + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] } - m := d.d[i] // middle digit u := byte('0') // upper digit - if i < upper.nd { - u = upper.d[i] + if ui < upper.nd { + u = upper.d[ui] } // Okay to round down (truncate) if lower has a different digit // or if lower is inclusive and is exactly the result of rounding // down (i.e., and we have reached the final digit of lower). - okdown := l != m || inclusive && i+1 == lower.nd + okdown := l != m || inclusive && li+1 == lower.nd + switch { + case upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + case upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + case upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } // 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 || m+1 < u || i+1 < upper.nd) + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+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) + d.Round(mi + 1) return case okdown: - d.RoundDown(i + 1) + d.RoundDown(mi + 1) return case okup: - d.RoundUp(i + 1) + d.RoundUp(mi + 1) return } } @@ -439,6 +485,89 @@ func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { return dst } +// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit) +func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { + if mant == 0 { + exp = 0 + } + + // Shift digits so leading 1 (if any) is at bit 1<<60. + mant <<= 60 - flt.mantbits + for mant != 0 && mant&(1<<60) == 0 { + mant <<= 1 + exp-- + } + + // Round if requested. + if prec >= 0 && prec < 15 { + shift := uint(prec * 4) + extra := (mant << shift) & (1<<60 - 1) + mant >>= 60 - shift + if extra|(mant&1) > 1<<59 { + mant++ + } + mant <<= 60 - shift + if mant&(1<<61) != 0 { + // Wrapped around. + mant >>= 1 + exp++ + } + } + + hex := lowerhex + if fmt == 'X' { + hex = upperhex + } + + // sign, 0x, leading digit + if neg { + dst = append(dst, '-') + } + dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1)) + + // .fraction + mant <<= 4 // remove leading 0 or 1 + if prec < 0 && mant != 0 { + dst = append(dst, '.') + for mant != 0 { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } else if prec > 0 { + dst = append(dst, '.') + for i := 0; i < prec; i++ { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } + + // p± + ch := byte('P') + if fmt == lower(fmt) { + ch = 'p' + } + dst = append(dst, ch) + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd or dddd + switch { + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + case exp < 1000: + dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + } + + return dst +} + func min(a, b int) int { if a < b { return a diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go index 1d3030b..755c986 100644 --- a/libgo/go/strconv/ftoa_test.go +++ b/libgo/go/strconv/ftoa_test.go @@ -30,9 +30,15 @@ var ftoatests = []ftoaTest{ {1, 'f', 5, "1.00000"}, {1, 'g', 5, "1"}, {1, 'g', -1, "1"}, + {1, 'x', -1, "0x1p+00"}, + {1, 'x', 5, "0x1.00000p+00"}, {20, 'g', -1, "20"}, + {20, 'x', -1, "0x1.4p+04"}, {1234567.8, 'g', -1, "1.2345678e+06"}, + {1234567.8, 'x', -1, "0x1.2d687cccccccdp+20"}, {200000, 'g', -1, "200000"}, + {200000, 'x', -1, "0x1.86ap+17"}, + {200000, 'X', -1, "0X1.86AP+17"}, {2000000, 'g', -1, "2e+06"}, // g conversion and zero suppression @@ -50,6 +56,7 @@ var ftoatests = []ftoaTest{ {0, 'f', 5, "0.00000"}, {0, 'g', 5, "0"}, {0, 'g', -1, "0"}, + {0, 'x', 5, "0x0.00000p+00"}, {-1, 'e', 5, "-1.00000e+00"}, {-1, 'f', 5, "-1.00000"}, @@ -100,7 +107,8 @@ var ftoatests = []ftoaTest{ {32, 'g', -1, "32"}, {32, 'g', 0, "3e+01"}, - {100, 'x', -1, "%x"}, + {100, 'x', -1, "0x1.9p+06"}, + {100, 'y', -1, "%y"}, {math.NaN(), 'g', -1, "NaN"}, {-math.NaN(), 'g', -1, "NaN"}, @@ -128,6 +136,27 @@ var ftoatests = []ftoaTest{ // Issue 2625. {383260575764816448, 'f', 0, "383260575764816448"}, {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + + // Issue 29491. + {498484681984085570, 'f', -1, "498484681984085570"}, + {-5.8339553793802237e+23, 'g', -1, "-5.8339553793802237e+23"}, + + // rounding + {2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"}, + {2.275555555555555, 'x', 0, "0x1p+01"}, + {2.275555555555555, 'x', 2, "0x1.23p+01"}, + {2.275555555555555, 'x', 16, "0x1.23456789abcde000p+01"}, + {2.275555555555555, 'x', 21, "0x1.23456789abcde00000000p+01"}, + {2.2755555510520935, 'x', -1, "0x1.2345678p+01"}, + {2.2755555510520935, 'x', 6, "0x1.234568p+01"}, + {2.275555431842804, 'x', -1, "0x1.2345668p+01"}, + {2.275555431842804, 'x', 6, "0x1.234566p+01"}, + {3.999969482421875, 'x', -1, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 4, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 3, "0x1.000p+02"}, + {3.999969482421875, 'x', 2, "0x1.00p+02"}, + {3.999969482421875, 'x', 1, "0x1.0p+02"}, + {3.999969482421875, 'x', 0, "0x1p+02"}, } func TestFtoa(t *testing.T) { diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go index f537ba4..a8dfdb2 100644 --- a/libgo/go/strconv/isprint.go +++ b/libgo/go/strconv/isprint.go @@ -6,7 +6,7 @@ package strconv -// (456+140+86)*2 + (396)*4 = 2948 bytes +// (448+137+90)*2 + (418)*4 = 3022 bytes var isPrint16 = []uint16{ 0x0020, 0x007e, @@ -16,17 +16,17 @@ var isPrint16 = []uint16{ 0x0559, 0x058a, 0x058d, 0x05c7, 0x05d0, 0x05ea, - 0x05f0, 0x05f4, + 0x05ef, 0x05f4, 0x0606, 0x061b, 0x061e, 0x070d, 0x0710, 0x074a, 0x074d, 0x07b1, 0x07c0, 0x07fa, - 0x0800, 0x082d, + 0x07fd, 0x082d, 0x0830, 0x085b, 0x085e, 0x086a, 0x08a0, 0x08bd, - 0x08d4, 0x098c, + 0x08d3, 0x098c, 0x098f, 0x0990, 0x0993, 0x09b2, 0x09b6, 0x09b9, @@ -35,7 +35,7 @@ var isPrint16 = []uint16{ 0x09cb, 0x09ce, 0x09d7, 0x09d7, 0x09dc, 0x09e3, - 0x09e6, 0x09fd, + 0x09e6, 0x09fe, 0x0a01, 0x0a0a, 0x0a0f, 0x0a10, 0x0a13, 0x0a39, @@ -44,7 +44,7 @@ var isPrint16 = []uint16{ 0x0a4b, 0x0a4d, 0x0a51, 0x0a51, 0x0a59, 0x0a5e, - 0x0a66, 0x0a75, + 0x0a66, 0x0a76, 0x0a81, 0x0ab9, 0x0abc, 0x0acd, 0x0ad0, 0x0ad0, @@ -126,7 +126,7 @@ var isPrint16 = []uint16{ 0x17f0, 0x17f9, 0x1800, 0x180d, 0x1810, 0x1819, - 0x1820, 0x1877, + 0x1820, 0x1878, 0x1880, 0x18aa, 0x18b0, 0x18f5, 0x1900, 0x192b, @@ -149,7 +149,8 @@ var isPrint16 = []uint16{ 0x1bfc, 0x1c37, 0x1c3b, 0x1c49, 0x1c4d, 0x1c88, - 0x1cc0, 0x1cc7, + 0x1c90, 0x1cba, + 0x1cbd, 0x1cc7, 0x1cd0, 0x1cf9, 0x1d00, 0x1f15, 0x1f18, 0x1f1d, @@ -170,38 +171,33 @@ var isPrint16 = []uint16{ 0x2440, 0x244a, 0x2460, 0x2b73, 0x2b76, 0x2b95, - 0x2b98, 0x2bb9, - 0x2bbd, 0x2bd2, - 0x2bec, 0x2bef, - 0x2c00, 0x2cf3, + 0x2b98, 0x2cf3, 0x2cf9, 0x2d27, 0x2d2d, 0x2d2d, 0x2d30, 0x2d67, 0x2d6f, 0x2d70, 0x2d7f, 0x2d96, - 0x2da0, 0x2e49, + 0x2da0, 0x2e4e, 0x2e80, 0x2ef3, 0x2f00, 0x2fd5, 0x2ff0, 0x2ffb, 0x3001, 0x3096, 0x3099, 0x30ff, - 0x3105, 0x312e, - 0x3131, 0x31ba, + 0x3105, 0x31ba, 0x31c0, 0x31e3, 0x31f0, 0x4db5, - 0x4dc0, 0x9fea, + 0x4dc0, 0x9fef, 0xa000, 0xa48c, 0xa490, 0xa4c6, 0xa4d0, 0xa62b, 0xa640, 0xa6f7, - 0xa700, 0xa7b7, + 0xa700, 0xa7b9, 0xa7f7, 0xa82b, 0xa830, 0xa839, 0xa840, 0xa877, 0xa880, 0xa8c5, 0xa8ce, 0xa8d9, - 0xa8e0, 0xa8fd, - 0xa900, 0xa953, + 0xa8e0, 0xa953, 0xa95f, 0xa97c, 0xa980, 0xa9d9, 0xa9de, 0xaa36, @@ -245,8 +241,6 @@ var isNotPrint16 = []uint16{ 0x038d, 0x03a2, 0x0530, - 0x0560, - 0x0588, 0x0590, 0x06dd, 0x083f, @@ -283,14 +277,12 @@ var isNotPrint16 = []uint16{ 0x0b9b, 0x0b9d, 0x0bc9, - 0x0c04, 0x0c0d, 0x0c11, 0x0c29, 0x0c45, 0x0c49, 0x0c57, - 0x0c84, 0x0c8d, 0x0c91, 0x0ca9, @@ -350,6 +342,7 @@ var isNotPrint16 = []uint16{ 0x1ff5, 0x208f, 0x2bc9, + 0x2bff, 0x2c2f, 0x2c5f, 0x2d26, @@ -363,10 +356,10 @@ var isNotPrint16 = []uint16{ 0x2ddf, 0x2e9a, 0x3040, + 0x3130, 0x318f, 0x321f, 0x32ff, - 0xa7af, 0xa9ce, 0xa9ff, 0xab27, @@ -421,9 +414,9 @@ var isPrint32 = []uint32{ 0x010980, 0x0109b7, 0x0109bc, 0x0109cf, 0x0109d2, 0x010a06, - 0x010a0c, 0x010a33, + 0x010a0c, 0x010a35, 0x010a38, 0x010a3a, - 0x010a3f, 0x010a47, + 0x010a3f, 0x010a48, 0x010a50, 0x010a58, 0x010a60, 0x010a9f, 0x010ac0, 0x010ae6, @@ -437,14 +430,17 @@ var isPrint32 = []uint32{ 0x010c00, 0x010c48, 0x010c80, 0x010cb2, 0x010cc0, 0x010cf2, - 0x010cfa, 0x010cff, + 0x010cfa, 0x010d27, + 0x010d30, 0x010d39, 0x010e60, 0x010e7e, + 0x010f00, 0x010f27, + 0x010f30, 0x010f59, 0x011000, 0x01104d, 0x011052, 0x01106f, 0x01107f, 0x0110c1, 0x0110d0, 0x0110e8, 0x0110f0, 0x0110f9, - 0x011100, 0x011143, + 0x011100, 0x011146, 0x011150, 0x011176, 0x011180, 0x0111cd, 0x0111d0, 0x0111f4, @@ -454,8 +450,7 @@ var isPrint32 = []uint32{ 0x0112f0, 0x0112f9, 0x011300, 0x01130c, 0x01130f, 0x011310, - 0x011313, 0x011339, - 0x01133c, 0x011344, + 0x011313, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, 0x011350, 0x011350, @@ -463,7 +458,7 @@ var isPrint32 = []uint32{ 0x01135d, 0x011363, 0x011366, 0x01136c, 0x011370, 0x011374, - 0x011400, 0x01145d, + 0x011400, 0x01145e, 0x011480, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, @@ -473,9 +468,10 @@ var isPrint32 = []uint32{ 0x011660, 0x01166c, 0x011680, 0x0116b7, 0x0116c0, 0x0116c9, - 0x011700, 0x011719, + 0x011700, 0x01171a, 0x01171d, 0x01172b, 0x011730, 0x01173f, + 0x011800, 0x01183b, 0x0118a0, 0x0118f2, 0x0118ff, 0x0118ff, 0x011a00, 0x011a47, @@ -489,6 +485,9 @@ var isPrint32 = []uint32{ 0x011d00, 0x011d36, 0x011d3a, 0x011d47, 0x011d50, 0x011d59, + 0x011d60, 0x011d98, + 0x011da0, 0x011da9, + 0x011ee0, 0x011ef8, 0x012000, 0x012399, 0x012400, 0x012474, 0x012480, 0x012543, @@ -502,11 +501,12 @@ var isPrint32 = []uint32{ 0x016b00, 0x016b45, 0x016b50, 0x016b77, 0x016b7d, 0x016b8f, + 0x016e40, 0x016e9a, 0x016f00, 0x016f44, 0x016f50, 0x016f7e, 0x016f8f, 0x016f9f, 0x016fe0, 0x016fe1, - 0x017000, 0x0187ec, + 0x017000, 0x0187f1, 0x018800, 0x018af2, 0x01b000, 0x01b11e, 0x01b170, 0x01b2fb, @@ -520,8 +520,9 @@ var isPrint32 = []uint32{ 0x01d129, 0x01d172, 0x01d17b, 0x01d1e8, 0x01d200, 0x01d245, + 0x01d2e0, 0x01d2f3, 0x01d300, 0x01d356, - 0x01d360, 0x01d371, + 0x01d360, 0x01d378, 0x01d400, 0x01d49f, 0x01d4a2, 0x01d4a2, 0x01d4a5, 0x01d4a6, @@ -538,6 +539,7 @@ var isPrint32 = []uint32{ 0x01e900, 0x01e94a, 0x01e950, 0x01e959, 0x01e95e, 0x01e95f, + 0x01ec71, 0x01ecb4, 0x01ee00, 0x01ee24, 0x01ee27, 0x01ee3b, 0x01ee42, 0x01ee42, @@ -560,20 +562,22 @@ var isPrint32 = []uint32{ 0x01f260, 0x01f265, 0x01f300, 0x01f6d4, 0x01f6e0, 0x01f6ec, - 0x01f6f0, 0x01f6f8, + 0x01f6f0, 0x01f6f9, 0x01f700, 0x01f773, - 0x01f780, 0x01f7d4, + 0x01f780, 0x01f7d8, 0x01f800, 0x01f80b, 0x01f810, 0x01f847, 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, 0x01f900, 0x01f90b, - 0x01f910, 0x01f94c, - 0x01f950, 0x01f96b, - 0x01f980, 0x01f997, - 0x01f9c0, 0x01f9c0, - 0x01f9d0, 0x01f9e6, + 0x01f910, 0x01f970, + 0x01f973, 0x01f976, + 0x01f97a, 0x01f9a2, + 0x01f9b0, 0x01f9b9, + 0x01f9c0, 0x01f9c2, + 0x01f9d0, 0x01f9ff, + 0x01fa60, 0x01fa6d, 0x020000, 0x02a6d6, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, @@ -609,9 +613,9 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0x1329, 0x1331, 0x1334, + 0x133a, 0x145a, 0x145c, - 0x1a9d, 0x1c09, 0x1c37, 0x1ca8, @@ -619,6 +623,10 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0x1d0a, 0x1d3b, 0x1d3e, + 0x1d66, + 0x1d69, + 0x1d8f, + 0x1d92, 0x246f, 0x6a5f, 0x6b5a, @@ -668,8 +676,8 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0xeeaa, 0xf0c0, 0xf0d0, - 0xf12f, 0xf93f, + 0xf97b, } // isGraphic lists the graphic runes not matched by IsPrint. diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go index 6cd2f93..b50496a 100644 --- a/libgo/go/strconv/quote.go +++ b/libgo/go/strconv/quote.go @@ -11,7 +11,10 @@ import ( "unicode/utf8" ) -const lowerhex = "0123456789abcdef" +const ( + lowerhex = "0123456789abcdef" + upperhex = "0123456789ABCDEF" +) func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string { return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly)) @@ -22,6 +25,13 @@ func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string { } func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte { + // Often called with big strings, so preallocate. If there's quoting, + // this is conservative but still helps a lot. + if cap(buf)-len(buf) < len(s) { + nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1) + copy(nBuf, buf) + buf = nBuf + } buf = append(buf, quote) for width := 0; len(s) > 0; s = s[width:] { r := rune(s[0]) diff --git a/libgo/go/strconv/strconv_test.go b/libgo/go/strconv/strconv_test.go index ebec0cc..7619f90 100644 --- a/libgo/go/strconv/strconv_test.go +++ b/libgo/go/strconv/strconv_test.go @@ -30,6 +30,9 @@ var ( AppendFloat(localBuf[:0], 1.23, 'g', 5, 64) }}, {0, `AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64)`, func() { AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64) }}, + // In practice we see 7 for the next one, but allow some slop. + // Before pre-allocation in appendQuotedWith, we saw 39. + {10, `AppendQuoteToASCII(nil, oneMB)`, func() { AppendQuoteToASCII(nil, string(oneMB)) }}, {0, `ParseFloat("123.45", 64)`, func() { ParseFloat("123.45", 64) }}, {0, `ParseFloat("123.456789123456789", 64)`, func() { ParseFloat("123.456789123456789", 64) }}, {0, `ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64)`, func() { @@ -41,6 +44,8 @@ var ( } ) +var oneMB []byte // Will be allocated to 1MB of random data by TestCountMallocs. + func TestCountMallocs(t *testing.T) { if runtime.Compiler == "gccgo" { t.Skip("skipping on gccgo until escape analysis is turned on") @@ -51,6 +56,11 @@ func TestCountMallocs(t *testing.T) { if runtime.GOMAXPROCS(0) > 1 { t.Skip("skipping; GOMAXPROCS>1") } + // Allocate a big messy buffer for AppendQuoteToASCII's test. + oneMB = make([]byte, 1e6) + for i := range oneMB { + oneMB[i] = byte(i) + } for _, mt := range mallocTest { allocs := testing.AllocsPerRun(100, mt.fn) if max := float64(mt.count); allocs > max { |