diff options
| author | Robert Griesemer <gri@golang.org> | 2015-05-28 17:38:05 -0700 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2015-05-29 17:11:43 +0000 |
| commit | a63b1806aa7484d744e79cd2f6d8e3bf73c4092c (patch) | |
| tree | 4a03914612fb69dfd9725860d9cd3f9128c1fb7b /src/math/big/floatconv.go | |
| parent | 9b3d9230aac0e8433add721a67f22ad6c27267ed (diff) | |
| download | go-a63b1806aa7484d744e79cd2f6d8e3bf73c4092c.tar.xz | |
math/big: remove (*Float).Scan, ScanFloat; more robust (*Float).Parse
- (*Float).Scan conflicted with fmt.Scanner.Scan; it was also only used
internally. Removed it, as well as the companion ScanFloat function.
- (*Float).Parse (and thus ParseFloat) can now also parse infinities.
As a result, more code could be simplified.
- Fixed a bug in rounding (round may implicitly be called for infinite
values). Found via existing test cases, after simplifying some code.
- Added more test cases.
Fixes issue #10938.
Change-Id: I1df97821654f034965ba8b82b272e52e6dc427f1
Reviewed-on: https://go-review.googlesource.com/10498
Reviewed-by: Alan Donovan <adonovan@google.com>
Diffstat (limited to 'src/math/big/floatconv.go')
| -rw-r--r-- | src/math/big/floatconv.go | 118 |
1 files changed, 56 insertions, 62 deletions
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go index dc62b450db..4a070ca64d 100644 --- a/src/math/big/floatconv.go +++ b/src/math/big/floatconv.go @@ -14,60 +14,19 @@ import ( // SetString sets z to the value of s and returns z and a boolean indicating // success. s must be a floating-point number of the same format as accepted -// by Scan, with number prefixes permitted. +// by Parse, with base argument 0. func (z *Float) SetString(s string) (*Float, bool) { - r := strings.NewReader(s) - - f, _, err := z.Scan(r, 0) - if err != nil { - return nil, false - } - - // there should be no unread characters left - if _, err = r.ReadByte(); err != io.EOF { - return nil, false + if f, _, err := z.Parse(s, 0); err == nil { + return f, true } - - return f, true + return nil, false } -// Scan scans the number corresponding to the longest possible prefix -// of r representing a floating-point number with a mantissa in the -// given conversion base (the exponent is always a decimal number). -// It sets z to the (possibly rounded) value of the corresponding -// floating-point number, and returns z, the actual base b, and an -// error err, if any. If z's precision is 0, it is changed to 64 -// before rounding takes effect. The number must be of the form: -// -// number = [ sign ] [ prefix ] mantissa [ exponent ] . -// sign = "+" | "-" . -// prefix = "0" ( "x" | "X" | "b" | "B" ) . -// mantissa = digits | digits "." [ digits ] | "." digits . -// exponent = ( "E" | "e" | "p" ) [ sign ] digits . -// digits = digit { digit } . -// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . -// -// The base argument must be 0, 2, 10, or 16. Providing an invalid base -// argument will lead to a run-time panic. -// -// For base 0, the number prefix determines the actual base: A prefix of -// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects -// base 2; otherwise, the actual base is 10 and no prefix is accepted. -// The octal prefix "0" is not supported (a leading "0" is simply -// considered a "0"). -// -// A "p" exponent indicates a binary (rather then decimal) exponent; -// for instance "0x1.fffffffffffffp1023" (using base 0) represents the -// maximum float64 value. For hexadecimal mantissae, the exponent must -// be binary, if present (an "e" or "E" exponent indicator cannot be -// distinguished from a mantissa digit). -// -// The returned *Float f is nil and the value of z is valid but not -// defined if an error is reported. -// -// BUG(gri) The Float.Scan signature conflicts with Scan(s fmt.ScanState, ch rune) error. -// (https://github.com/golang/go/issues/10938) -func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) { +// scan is like Parse but reads the longest possible prefix representing a valid +// floating point number from an io.ByteScanner rather than a string. It serves +// as the implementation of Parse. It does not recognize ±Inf and does not expect +// EOF at the end. +func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) { prec := z.prec if prec == 0 { prec = 64 @@ -211,14 +170,55 @@ func (z *Float) pow10(n int64) *Float { return z } -// Parse is like z.Scan(r, base), but instead of reading from an -// io.ByteScanner, it parses the string s. An error is also returned -// if the string contains invalid or trailing bytes not belonging to -// the number. +// Parse parses s which must contain a text representation of a floating- +// point number with a mantissa in the given conversion base (the exponent +// is always a decimal number), or a string representing an infinite value. +// +// It sets z to the (possibly rounded) value of the corresponding floating- +// point value, and returns z, the actual base b, and an error err, if any. +// If z's precision is 0, it is changed to 64 before rounding takes effect. +// The number must be of the form: +// +// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity . +// sign = "+" | "-" . +// prefix = "0" ( "x" | "X" | "b" | "B" ) . +// mantissa = digits | digits "." [ digits ] | "." digits . +// exponent = ( "E" | "e" | "p" ) [ sign ] digits . +// digits = digit { digit } . +// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . +// infinity = [ sign ] ( "inf" | "Inf" ) . +// +// The base argument must be 0, 2, 10, or 16. Providing an invalid base +// argument will lead to a run-time panic. +// +// For base 0, the number prefix determines the actual base: A prefix of +// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects +// base 2; otherwise, the actual base is 10 and no prefix is accepted. +// The octal prefix "0" is not supported (a leading "0" is simply +// considered a "0"). +// +// A "p" exponent indicates a binary (rather then decimal) exponent; +// for instance "0x1.fffffffffffffp1023" (using base 0) represents the +// maximum float64 value. For hexadecimal mantissae, the exponent must +// be binary, if present (an "e" or "E" exponent indicator cannot be +// distinguished from a mantissa digit). +// +// The returned *Float f is nil and the value of z is valid but not +// defined if an error is reported. +// func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { - r := strings.NewReader(s) + // scan doesn't handle ±Inf + if len(s) == 3 && (s == "Inf" || s == "inf") { + f = z.SetInf(false) + return + } + if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") { + f = z.SetInf(s[0] == '-') + return + } - if f, b, err = z.Scan(r, base); err != nil { + r := strings.NewReader(s) + if f, b, err = z.scan(r, base); err != nil { return } @@ -232,12 +232,6 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { return } -// ScanFloat is like f.Scan(r, base) with f set to the given precision -// and rounding mode. -func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) { - return new(Float).SetPrec(prec).SetMode(mode).Scan(r, base) -} - // ParseFloat is like f.Parse(s, base) with f set to the given precision // and rounding mode. func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) { |
