mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			271 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			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 rat-to-string conversion functions.
 | 
						|
 | 
						|
package big
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
func ratTok(ch rune) bool {
 | 
						|
	return strings.ContainsRune("+-/0123456789.eE", ch)
 | 
						|
}
 | 
						|
 | 
						|
// Scan is a support routine for fmt.Scanner. It accepts the formats
 | 
						|
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
 | 
						|
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
 | 
						|
	tok, err := s.Token(true, ratTok)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if !strings.ContainsRune("efgEFGv", ch) {
 | 
						|
		return errors.New("Rat.Scan: invalid verb")
 | 
						|
	}
 | 
						|
	if _, ok := z.SetString(string(tok)); !ok {
 | 
						|
		return errors.New("Rat.Scan: invalid syntax")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// SetString sets z to the value of s and returns z and a boolean indicating
 | 
						|
// success. s can be given as a fraction "a/b" or as a floating-point number
 | 
						|
// optionally followed by an exponent. If the operation failed, the value of
 | 
						|
// z is undefined but the returned value is nil.
 | 
						|
func (z *Rat) SetString(s string) (*Rat, bool) {
 | 
						|
	if len(s) == 0 {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
	// len(s) > 0
 | 
						|
 | 
						|
	// parse fraction a/b, if any
 | 
						|
	if sep := strings.Index(s, "/"); sep >= 0 {
 | 
						|
		if _, ok := z.a.SetString(s[:sep], 0); !ok {
 | 
						|
			return nil, false
 | 
						|
		}
 | 
						|
		s = s[sep+1:]
 | 
						|
		var err error
 | 
						|
		if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
 | 
						|
			return nil, false
 | 
						|
		}
 | 
						|
		if len(z.b.abs) == 0 {
 | 
						|
			return nil, false
 | 
						|
		}
 | 
						|
		return z.norm(), true
 | 
						|
	}
 | 
						|
 | 
						|
	// parse floating-point number
 | 
						|
	r := strings.NewReader(s)
 | 
						|
 | 
						|
	// sign
 | 
						|
	neg, err := scanSign(r)
 | 
						|
	if err != nil {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
 | 
						|
	// mantissa
 | 
						|
	var ecorr int
 | 
						|
	z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
 | 
						|
	if err != nil {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
 | 
						|
	// exponent
 | 
						|
	var exp int64
 | 
						|
	exp, _, err = scanExponent(r, false)
 | 
						|
	if err != nil {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
 | 
						|
	// there should be no unread characters left
 | 
						|
	if _, err = r.ReadByte(); err != io.EOF {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
 | 
						|
	// special-case 0 (see also issue #16176)
 | 
						|
	if len(z.a.abs) == 0 {
 | 
						|
		return z, true
 | 
						|
	}
 | 
						|
	// len(z.a.abs) > 0
 | 
						|
 | 
						|
	// correct exponent
 | 
						|
	if ecorr < 0 {
 | 
						|
		exp += int64(ecorr)
 | 
						|
	}
 | 
						|
 | 
						|
	// compute exponent power
 | 
						|
	expabs := exp
 | 
						|
	if expabs < 0 {
 | 
						|
		expabs = -expabs
 | 
						|
	}
 | 
						|
	powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
 | 
						|
 | 
						|
	// complete fraction
 | 
						|
	if exp < 0 {
 | 
						|
		z.b.abs = powTen
 | 
						|
		z.norm()
 | 
						|
	} else {
 | 
						|
		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
 | 
						|
		z.b.abs = z.b.abs[:0]
 | 
						|
	}
 | 
						|
 | 
						|
	z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
 | 
						|
 | 
						|
	return z, true
 | 
						|
}
 | 
						|
 | 
						|
// scanExponent scans the longest possible prefix of r representing a decimal
 | 
						|
// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
 | 
						|
// exponent base (10 or 2), or a read or syntax error, if any.
 | 
						|
//
 | 
						|
//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
 | 
						|
//	sign     = "+" | "-" .
 | 
						|
//	digits   = digit { digit } .
 | 
						|
//	digit    = "0" ... "9" .
 | 
						|
//
 | 
						|
// A binary exponent is only permitted if binExpOk is set.
 | 
						|
func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
 | 
						|
	base = 10
 | 
						|
 | 
						|
	var ch byte
 | 
						|
	if ch, err = r.ReadByte(); err != nil {
 | 
						|
		if err == io.EOF {
 | 
						|
			err = nil // no exponent; same as e0
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	switch ch {
 | 
						|
	case 'e', 'E':
 | 
						|
		// ok
 | 
						|
	case 'p':
 | 
						|
		if binExpOk {
 | 
						|
			base = 2
 | 
						|
			break // ok
 | 
						|
		}
 | 
						|
		fallthrough // binary exponent not permitted
 | 
						|
	default:
 | 
						|
		r.UnreadByte()
 | 
						|
		return // no exponent; same as e0
 | 
						|
	}
 | 
						|
 | 
						|
	var neg bool
 | 
						|
	if neg, err = scanSign(r); err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	var digits []byte
 | 
						|
	if neg {
 | 
						|
		digits = append(digits, '-')
 | 
						|
	}
 | 
						|
 | 
						|
	// no need to use nat.scan for exponent digits
 | 
						|
	// since we only care about int64 values - the
 | 
						|
	// from-scratch scan is easy enough and faster
 | 
						|
	for i := 0; ; i++ {
 | 
						|
		if ch, err = r.ReadByte(); err != nil {
 | 
						|
			if err != io.EOF || i == 0 {
 | 
						|
				return
 | 
						|
			}
 | 
						|
			err = nil
 | 
						|
			break // i > 0
 | 
						|
		}
 | 
						|
		if ch < '0' || '9' < ch {
 | 
						|
			if i == 0 {
 | 
						|
				r.UnreadByte()
 | 
						|
				err = fmt.Errorf("invalid exponent (missing digits)")
 | 
						|
				return
 | 
						|
			}
 | 
						|
			break // i > 0
 | 
						|
		}
 | 
						|
		digits = append(digits, ch)
 | 
						|
	}
 | 
						|
	// i > 0 => we have at least one digit
 | 
						|
 | 
						|
	exp, err = strconv.ParseInt(string(digits), 10, 64)
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// String returns a string representation of x in the form "a/b" (even if b == 1).
 | 
						|
func (x *Rat) String() string {
 | 
						|
	var buf []byte
 | 
						|
	buf = x.a.Append(buf, 10)
 | 
						|
	buf = append(buf, '/')
 | 
						|
	if len(x.b.abs) != 0 {
 | 
						|
		buf = x.b.Append(buf, 10)
 | 
						|
	} else {
 | 
						|
		buf = append(buf, '1')
 | 
						|
	}
 | 
						|
	return string(buf)
 | 
						|
}
 | 
						|
 | 
						|
// RatString returns a string representation of x in the form "a/b" if b != 1,
 | 
						|
// and in the form "a" if b == 1.
 | 
						|
func (x *Rat) RatString() string {
 | 
						|
	if x.IsInt() {
 | 
						|
		return x.a.String()
 | 
						|
	}
 | 
						|
	return x.String()
 | 
						|
}
 | 
						|
 | 
						|
// FloatString returns a string representation of x in decimal form with prec
 | 
						|
// digits of precision after the decimal point. The last digit is rounded to
 | 
						|
// nearest, with halves rounded away from zero.
 | 
						|
func (x *Rat) FloatString(prec int) string {
 | 
						|
	var buf []byte
 | 
						|
 | 
						|
	if x.IsInt() {
 | 
						|
		buf = x.a.Append(buf, 10)
 | 
						|
		if prec > 0 {
 | 
						|
			buf = append(buf, '.')
 | 
						|
			for i := prec; i > 0; i-- {
 | 
						|
				buf = append(buf, '0')
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return string(buf)
 | 
						|
	}
 | 
						|
	// x.b.abs != 0
 | 
						|
 | 
						|
	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
 | 
						|
 | 
						|
	p := natOne
 | 
						|
	if prec > 0 {
 | 
						|
		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
 | 
						|
	}
 | 
						|
 | 
						|
	r = r.mul(r, p)
 | 
						|
	r, r2 := r.div(nat(nil), r, x.b.abs)
 | 
						|
 | 
						|
	// see if we need to round up
 | 
						|
	r2 = r2.add(r2, r2)
 | 
						|
	if x.b.abs.cmp(r2) <= 0 {
 | 
						|
		r = r.add(r, natOne)
 | 
						|
		if r.cmp(p) >= 0 {
 | 
						|
			q = nat(nil).add(q, natOne)
 | 
						|
			r = nat(nil).sub(r, p)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if x.a.neg {
 | 
						|
		buf = append(buf, '-')
 | 
						|
	}
 | 
						|
	buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
 | 
						|
 | 
						|
	if prec > 0 {
 | 
						|
		buf = append(buf, '.')
 | 
						|
		rs := r.utoa(10)
 | 
						|
		for i := prec - len(rs); i > 0; i-- {
 | 
						|
			buf = append(buf, '0')
 | 
						|
		}
 | 
						|
		buf = append(buf, rs...)
 | 
						|
	}
 | 
						|
 | 
						|
	return string(buf)
 | 
						|
}
 |