blob: e41d447db0ead3a0514ca6e01ef9c513a98ecce2 [file] [log] [blame]
// Copyright 2015 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.
// This file implements float-to-string conversion functions.
package big
import (
"fmt"
"io"
"strconv"
"strings"
)
// 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.
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.ReadRune(); err != io.EOF {
return nil, false
}
return f, true
}
// 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 returns the corresponding Float f, the actual base b, and an
// error err, if any. 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 "p" exponent indicates power of 2 for the exponent; for instance "1.2p3"
// with base 0 or 10 corresponds to the value 1.2 * 2**3.
//
// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
// TODO(gri) What should the default precision be?
func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
// sign
z.neg, err = scanSign(r)
if err != nil {
return
}
// mantissa
var ecorr int // decimal exponent correction; valid if <= 0
z.mant, b, ecorr, err = z.mant.scan(r, base, true)
if err != nil {
return
}
// exponent
var exp int64
var ebase int
exp, ebase, err = scanExponent(r, true)
if err != nil {
return
}
// special-case 0
if len(z.mant) == 0 {
z.exp = 0
f = z
return
}
// len(z.mant) > 0
// determine binary (exp2) and decimal (exp) exponent
exp2 := int64(len(z.mant)*_W - int(fnorm(z.mant)))
if ebase == 2 {
exp2 += exp
exp = 0
}
if ecorr < 0 {
exp += int64(ecorr)
}
z.setExp(exp2)
if exp == 0 {
// no decimal exponent
z.round(0)
f = z
return
}
// exp != 0
// compute decimal exponent power
expabs := exp
if expabs < 0 {
expabs = -expabs
}
powTen := new(Float).SetInt(new(Int).SetBits(nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)))
// correct result
if exp < 0 {
z.uquo(z, powTen)
} else {
z.umul(z, powTen)
}
f = z
return
}
// Parse is like z.Scan(r, base), but instead of reading from an
// io.ByteScanner, it parses the string s. An error is returned if
// the string contains invalid or trailing bytes not belonging to
// the number.
func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
r := strings.NewReader(s)
if f, b, err = z.Scan(r, base); err != nil {
return
}
// entire string must have been consumed
if ch, err2 := r.ReadByte(); err2 == nil {
err = fmt.Errorf("expected end of string, found %q", ch)
} else if err2 != io.EOF {
err = err2
}
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) {
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.Precision() 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) Currently, Format does not accept negative precisions.
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(0) {
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): Currently, 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.Precision() bits in binary
// representation.
func (x *Float) bstring(buf []byte) []byte {
if x.neg {
buf = append(buf, '-')
}
if len(x.mant) == 0 {
return append(buf, '0')
}
// x != 0
// normalize mantissa
m := x.mant
t := uint(len(x.mant)*_W) - x.prec // 0 <= t < _W
if t > 0 {
m = nat(nil).shr(m, t)
}
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 len(x.mant) == 0 {
return append(buf, '0')
}
// x != 0
// mantissa is stored in normalized form
buf = append(buf, "0x."...)
buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
buf = append(buf, 'p')
return strconv.AppendInt(buf, int64(x.exp), 10)
}