...
Run Format

Source file src/math/big/floatconv.go

  // 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 string-to-Float conversion functions.
  
  package big
  
  import (
  	"fmt"
  	"io"
  	"strings"
  )
  
  var floatZero Float
  
  // 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 Parse, with base argument 0. The entire string (not just a prefix) must
  // be valid for success. If the operation failed, the value of z is undefined
  // but the returned value is nil.
  func (z *Float) SetString(s string) (*Float, bool) {
  	if f, _, err := z.Parse(s, 0); err == nil {
  		return f, true
  	}
  	return nil, false
  }
  
  // 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
  	}
  
  	// A reasonable value in case of an error.
  	z.form = zero
  
  	// sign
  	z.neg, err = scanSign(r)
  	if err != nil {
  		return
  	}
  
  	// mantissa
  	var fcount int // fractional digit count; valid if <= 0
  	z.mant, b, fcount, 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.prec = prec
  		z.acc = Exact
  		z.form = zero
  		f = z
  		return
  	}
  	// len(z.mant) > 0
  
  	// The mantissa may have a decimal point (fcount <= 0) and there
  	// may be a nonzero exponent exp. The decimal point amounts to a
  	// division by b**(-fcount). An exponent means multiplication by
  	// ebase**exp. Finally, mantissa normalization (shift left) requires
  	// a correcting multiplication by 2**(-shiftcount). Multiplications
  	// are commutative, so we can apply them in any order as long as there
  	// is no loss of precision. We only have powers of 2 and 10, and
  	// we split powers of 10 into the product of the same powers of
  	// 2 and 5. This reduces the size of the multiplication factor
  	// needed for base-10 exponents.
  
  	// normalize mantissa and determine initial exponent contributions
  	exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
  	exp5 := int64(0)
  
  	// determine binary or decimal exponent contribution of decimal point
  	if fcount < 0 {
  		// The mantissa has a "decimal" point ddd.dddd; and
  		// -fcount is the number of digits to the right of '.'.
  		// Adjust relevant exponent accordingly.
  		d := int64(fcount)
  		switch b {
  		case 10:
  			exp5 = d
  			fallthrough // 10**e == 5**e * 2**e
  		case 2:
  			exp2 += d
  		case 16:
  			exp2 += d * 4 // hexadecimal digits are 4 bits each
  		default:
  			panic("unexpected mantissa base")
  		}
  		// fcount consumed - not needed anymore
  	}
  
  	// take actual exponent into account
  	switch ebase {
  	case 10:
  		exp5 += exp
  		fallthrough
  	case 2:
  		exp2 += exp
  	default:
  		panic("unexpected exponent base")
  	}
  	// exp consumed - not needed anymore
  
  	// apply 2**exp2
  	if MinExp <= exp2 && exp2 <= MaxExp {
  		z.prec = prec
  		z.form = finite
  		z.exp = int32(exp2)
  		f = z
  	} else {
  		err = fmt.Errorf("exponent overflow")
  		return
  	}
  
  	if exp5 == 0 {
  		// no decimal exponent contribution
  		z.round(0)
  		return
  	}
  	// exp5 != 0
  
  	// apply 5**exp5
  	p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
  	if exp5 < 0 {
  		z.Quo(z, p.pow5(uint64(-exp5)))
  	} else {
  		z.Mul(z, p.pow5(uint64(exp5)))
  	}
  
  	return
  }
  
  // These powers of 5 fit into a uint64.
  //
  //	for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
  //		fmt.Println(q)
  //	}
  //
  var pow5tab = [...]uint64{
  	1,
  	5,
  	25,
  	125,
  	625,
  	3125,
  	15625,
  	78125,
  	390625,
  	1953125,
  	9765625,
  	48828125,
  	244140625,
  	1220703125,
  	6103515625,
  	30517578125,
  	152587890625,
  	762939453125,
  	3814697265625,
  	19073486328125,
  	95367431640625,
  	476837158203125,
  	2384185791015625,
  	11920928955078125,
  	59604644775390625,
  	298023223876953125,
  	1490116119384765625,
  	7450580596923828125,
  }
  
  // pow5 sets z to 5**n and returns z.
  // n must not be negative.
  func (z *Float) pow5(n uint64) *Float {
  	const m = uint64(len(pow5tab) - 1)
  	if n <= m {
  		return z.SetUint64(pow5tab[n])
  	}
  	// n > m
  
  	z.SetUint64(pow5tab[m])
  	n -= m
  
  	// use more bits for f than for z
  	// TODO(gri) what is the right number?
  	f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
  
  	for n > 0 {
  		if n&1 != 0 {
  			z.Mul(z, f)
  		}
  		f.Mul(f, f)
  		n >>= 1
  	}
  
  	return z
  }
  
  // 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.
  // The entire string (not just a prefix) must be consumed for success.
  // 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) {
  	// 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
  	}
  
  	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
  }
  
  // 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)
  }
  
  var _ fmt.Scanner = &floatZero // *Float must implement fmt.Scanner
  
  // Scan is a support routine for fmt.Scanner; it sets z to the value of
  // the scanned number. It accepts formats whose verbs are supported by
  // fmt.Scan for floating point values, which are:
  // 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
  // Scan doesn't handle ±Inf.
  func (z *Float) Scan(s fmt.ScanState, ch rune) error {
  	s.SkipSpace()
  	_, _, err := z.scan(byteReader{s}, 0)
  	return err
  }
  

View as plain text