// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file implements float-to-string conversion functions.
+// This file implements string-to-Float conversion functions.
package big
import (
"fmt"
"io"
- "strconv"
"strings"
)
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
}
-
-// Format converts the floating-point number x to a string according
-// to the given format and precision prec. The format is one of:
-//
-// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
-// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
-// 'f' -ddddd.dddd, no exponent
-// 'g' like 'e' for large exponents, like 'f' otherwise
-// 'G' like 'E' for large exponents, like 'f' otherwise
-// 'b' -ddddddp±dd, binary exponent
-// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa
-//
-// For the binary exponent formats, the mantissa is printed in normalized form:
-//
-// 'b' decimal integer mantissa using x.Prec() bits, or -0
-// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
-//
-// 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. A negative precision selects the smallest
-// number of digits necessary such that ParseFloat will return f exactly.
-// The prec value is ignored for the 'b' or 'p' format.
-//
-// BUG(gri) Float.Format does not accept negative precisions.
-// BUG(gri) The Float.Format signature conflicts with Format(f fmt.State, c rune).
-// (https://github.com/golang/go/issues/10938)
-func (x *Float) Format(format byte, prec int) string {
- const extra = 10 // TODO(gri) determine a good/better value here
- return string(x.Append(make([]byte, 0, prec+extra), format, prec))
-}
-
-// Append appends the string form of the floating-point number x,
-// as generated by x.Format, to buf and returns the extended buffer.
-func (x *Float) Append(buf []byte, format byte, prec int) []byte {
- // TODO(gri) factor out handling of sign?
-
- // Inf
- if x.IsInf() {
- var ch byte = '+'
- if x.neg {
- ch = '-'
- }
- buf = append(buf, ch)
- return append(buf, "Inf"...)
- }
-
- // easy formats
- switch format {
- case 'b':
- return x.bstring(buf)
- case 'p':
- return x.pstring(buf)
- }
-
- return x.bigFtoa(buf, format, prec)
-}
-
-// BUG(gri): Float.String uses x.Format('g', 10) rather than x.Format('g', -1).
-func (x *Float) String() string {
- return x.Format('g', 10)
-}
-
-// bstring appends the string of x in the format ["-"] mantissa "p" exponent
-// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
-// and returns the extended buffer.
-// The mantissa is normalized such that is uses x.Prec() bits in binary
-// representation.
-func (x *Float) bstring(buf []byte) []byte {
- if x.neg {
- buf = append(buf, '-')
- }
- if x.form == zero {
- return append(buf, '0')
- }
-
- if debugFloat && x.form != finite {
- panic("non-finite float")
- }
- // x != 0
-
- // adjust mantissa to use exactly x.prec bits
- m := x.mant
- switch w := uint32(len(x.mant)) * _W; {
- case w < x.prec:
- m = nat(nil).shl(m, uint(x.prec-w))
- case w > x.prec:
- m = nat(nil).shr(m, uint(w-x.prec))
- }
-
- buf = append(buf, m.decimalString()...)
- buf = append(buf, 'p')
- e := int64(x.exp) - int64(x.prec)
- if e >= 0 {
- buf = append(buf, '+')
- }
- return strconv.AppendInt(buf, e, 10)
-}
-
-// pstring appends the string of x in the format ["-"] "0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
-// ad returns the extended buffer.
-// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
-func (x *Float) pstring(buf []byte) []byte {
- if x.neg {
- buf = append(buf, '-')
- }
- if x.form == zero {
- return append(buf, '0')
- }
-
- if debugFloat && x.form != finite {
- panic("non-finite float")
- }
- // x != 0
-
- // remove trailing 0 words early
- // (no need to convert to hex 0's and trim later)
- m := x.mant
- i := 0
- for i < len(m) && m[i] == 0 {
- i++
- }
- m = m[i:]
-
- buf = append(buf, "0x."...)
- buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
- buf = append(buf, 'p')
- if x.exp >= 0 {
- buf = append(buf, '+')
- }
- return strconv.AppendInt(buf, int64(x.exp), 10)
-}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file implements the 'e', 'f', 'g' floating-point formats.
-// It is closely following the corresponding implementation in
-// strconv/ftoa.go, but modified and simplified for big.Float.
-
-// Algorithm:
-// 1) convert Float to multiprecision decimal
-// 2) round to desired precision
-// 3) read digits out and format
+// This file implements Float-to-string conversion functions.
+// It is closely following the corresponding implementation
+// in strconv/ftoa.go, but modified and simplified for Float.
package big
-import "strconv"
+import (
+ "strconv"
+ "strings"
+)
-// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
+// Format converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
+// 'f' -ddddd.dddd, no exponent
+// 'g' like 'e' for large exponents, like 'f' otherwise
+// 'G' like 'E' for large exponents, like 'f' otherwise
+// 'b' -ddddddp±dd, binary exponent
+// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+// 'b' decimal integer mantissa using x.Prec() bits, or -0
+// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// 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. A negative precision selects the smallest
+// number of digits necessary such that ParseFloat will return f exactly.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Float.Format does not accept negative precisions.
+// BUG(gri) The Float.Format signature conflicts with Format(f fmt.State, c rune).
+// (https://github.com/golang/go/issues/10938)
+func (x *Float) Format(format byte, prec int) string {
+ const extra = 10 // TODO(gri) determine a good/better value here
+ return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+}
-// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
-func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
- if debugFloat && f.IsInf() {
- panic("non-finite float")
+// String formats x like x.Format('g', 10).
+func (x *Float) String() string {
+ return x.Format('g', 10)
+}
+
+// Append appends to buf the string form of the floating-point number x,
+// as generated by x.Format, and returns the extended buffer.
+func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
+ // sign
+ if x.neg {
+ buf = append(buf, '-')
+ }
+
+ // Inf
+ if x.IsInf() {
+ if !x.neg {
+ buf = append(buf, '+')
+ }
+ return append(buf, "Inf"...)
+ }
+
+ // pick off easy formats
+ switch fmt {
+ case 'b':
+ return x.fmtB(buf)
+ case 'p':
+ return x.fmtP(buf)
}
+ // Algorithm:
+ // 1) convert Float to multiprecision decimal
+ // 2) round to desired precision
+ // 3) read digits out and format
+
// 1) convert Float to multiprecision decimal
var mant nat
- if f.form == finite {
- mant = f.mant
+ if x.form == finite {
+ mant = x.mant
}
var d decimal
- d.init(mant, int(f.exp)-f.mant.bitLen())
+ d.init(mant, int(x.exp)-x.mant.bitLen())
// 2) round to desired precision
shortest := false
// 3) read digits out and format
switch fmt {
case 'e', 'E':
- return fmtE(buf, fmt, prec, f.neg, d)
+ return fmtE(buf, fmt, prec, d)
case 'f':
- return fmtF(buf, prec, f.neg, d)
+ return fmtF(buf, prec, d)
case 'g', 'G':
// trim trailing fractional zeros in %e format
eprec := prec
if prec > len(d.mant) {
prec = len(d.mant)
}
- return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
+ return fmtE(buf, fmt+'e'-'g', prec-1, d)
}
if prec > d.exp {
prec = len(d.mant)
}
- return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
+ return fmtF(buf, max(prec-d.exp, 0), d)
}
// unknown format
+ if x.neg {
+ buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
+ }
return append(buf, '%', fmt)
}
-// %e: -d.ddddde±dd
-func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
- // sign
- if neg {
- buf = append(buf, '-')
- }
-
+// %e: d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
// first digit
ch := byte('0')
if len(d.mant) > 0 {
return strconv.AppendInt(buf, exp, 10)
}
-// %f: -ddddddd.ddddd
-func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
- // sign
- if neg {
- buf = append(buf, '-')
- }
-
+// %f: ddddddd.ddddd
+func fmtF(buf []byte, prec int, d decimal) []byte {
// integer, padded with zeros as needed
if d.exp > 0 {
m := min(len(d.mant), d.exp)
return buf
}
+// fmtB appends the string of x in the format mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or 0" if x is zero,
+// and returns the extended buffer.
+// The mantissa is normalized such that is uses x.Prec() bits in binary
+// representation.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtB(buf []byte) []byte {
+ if x.form == zero {
+ return append(buf, '0')
+ }
+
+ if debugFloat && x.form != finite {
+ panic("non-finite float")
+ }
+ // x != 0
+
+ // adjust mantissa to use exactly x.prec bits
+ m := x.mant
+ switch w := uint32(len(x.mant)) * _W; {
+ case w < x.prec:
+ m = nat(nil).shl(m, uint(x.prec-w))
+ case w > x.prec:
+ m = nat(nil).shr(m, uint(w-x.prec))
+ }
+
+ buf = append(buf, m.decimalString()...)
+ buf = append(buf, 'p')
+ e := int64(x.exp) - int64(x.prec)
+ if e >= 0 {
+ buf = append(buf, '+')
+ }
+ return strconv.AppendInt(buf, e, 10)
+}
+
+// fmtP appends the string of x in the format 0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
+// ad returns the extended buffer.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtP(buf []byte) []byte {
+ if x.form == zero {
+ return append(buf, '0')
+ }
+
+ if debugFloat && x.form != finite {
+ panic("non-finite float")
+ }
+ // x != 0
+
+ // remove trailing 0 words early
+ // (no need to convert to hex 0's and trim later)
+ m := x.mant
+ i := 0
+ for i < len(m) && m[i] == 0 {
+ i++
+ }
+ m = m[i:]
+
+ buf = append(buf, "0x."...)
+ buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
+ buf = append(buf, 'p')
+ if x.exp >= 0 {
+ buf = append(buf, '+')
+ }
+ return strconv.AppendInt(buf, int64(x.exp), 10)
+}
+
func min(x, y int) int {
if x < y {
return x