Home | History | Annotate | Download | only in big
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // This file implements rat-to-string conversion functions.
      6 
      7 package big
      8 
      9 import (
     10 	"errors"
     11 	"fmt"
     12 	"io"
     13 	"strconv"
     14 	"strings"
     15 )
     16 
     17 func ratTok(ch rune) bool {
     18 	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
     19 }
     20 
     21 // Scan is a support routine for fmt.Scanner. It accepts the formats
     22 // 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
     23 func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
     24 	tok, err := s.Token(true, ratTok)
     25 	if err != nil {
     26 		return err
     27 	}
     28 	if strings.IndexRune("efgEFGv", ch) < 0 {
     29 		return errors.New("Rat.Scan: invalid verb")
     30 	}
     31 	if _, ok := z.SetString(string(tok)); !ok {
     32 		return errors.New("Rat.Scan: invalid syntax")
     33 	}
     34 	return nil
     35 }
     36 
     37 // SetString sets z to the value of s and returns z and a boolean indicating
     38 // success. s can be given as a fraction "a/b" or as a floating-point number
     39 // optionally followed by an exponent. If the operation failed, the value of
     40 // z is undefined but the returned value is nil.
     41 func (z *Rat) SetString(s string) (*Rat, bool) {
     42 	if len(s) == 0 {
     43 		return nil, false
     44 	}
     45 	// len(s) > 0
     46 
     47 	// parse fraction a/b, if any
     48 	if sep := strings.Index(s, "/"); sep >= 0 {
     49 		if _, ok := z.a.SetString(s[:sep], 0); !ok {
     50 			return nil, false
     51 		}
     52 		s = s[sep+1:]
     53 		var err error
     54 		if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
     55 			return nil, false
     56 		}
     57 		if len(z.b.abs) == 0 {
     58 			return nil, false
     59 		}
     60 		return z.norm(), true
     61 	}
     62 
     63 	// parse floating-point number
     64 	r := strings.NewReader(s)
     65 
     66 	// sign
     67 	neg, err := scanSign(r)
     68 	if err != nil {
     69 		return nil, false
     70 	}
     71 
     72 	// mantissa
     73 	var ecorr int
     74 	z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
     75 	if err != nil {
     76 		return nil, false
     77 	}
     78 
     79 	// exponent
     80 	var exp int64
     81 	exp, _, err = scanExponent(r, false)
     82 	if err != nil {
     83 		return nil, false
     84 	}
     85 
     86 	// there should be no unread characters left
     87 	if _, err = r.ReadByte(); err != io.EOF {
     88 		return nil, false
     89 	}
     90 
     91 	// correct exponent
     92 	if ecorr < 0 {
     93 		exp += int64(ecorr)
     94 	}
     95 
     96 	// compute exponent power
     97 	expabs := exp
     98 	if expabs < 0 {
     99 		expabs = -expabs
    100 	}
    101 	powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
    102 
    103 	// complete fraction
    104 	if exp < 0 {
    105 		z.b.abs = powTen
    106 		z.norm()
    107 	} else {
    108 		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
    109 		z.b.abs = z.b.abs[:0]
    110 	}
    111 
    112 	z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
    113 
    114 	return z, true
    115 }
    116 
    117 // scanExponent scans the longest possible prefix of r representing a decimal
    118 // ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
    119 // exponent base (10 or 2), or a read or syntax error, if any.
    120 //
    121 //	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
    122 //	sign     = "+" | "-" .
    123 //	digits   = digit { digit } .
    124 //	digit    = "0" ... "9" .
    125 //
    126 // A binary exponent is only permitted if binExpOk is set.
    127 func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
    128 	base = 10
    129 
    130 	var ch byte
    131 	if ch, err = r.ReadByte(); err != nil {
    132 		if err == io.EOF {
    133 			err = nil // no exponent; same as e0
    134 		}
    135 		return
    136 	}
    137 
    138 	switch ch {
    139 	case 'e', 'E':
    140 		// ok
    141 	case 'p':
    142 		if binExpOk {
    143 			base = 2
    144 			break // ok
    145 		}
    146 		fallthrough // binary exponent not permitted
    147 	default:
    148 		r.UnreadByte()
    149 		return // no exponent; same as e0
    150 	}
    151 
    152 	var neg bool
    153 	if neg, err = scanSign(r); err != nil {
    154 		return
    155 	}
    156 
    157 	var digits []byte
    158 	if neg {
    159 		digits = append(digits, '-')
    160 	}
    161 
    162 	// no need to use nat.scan for exponent digits
    163 	// since we only care about int64 values - the
    164 	// from-scratch scan is easy enough and faster
    165 	for i := 0; ; i++ {
    166 		if ch, err = r.ReadByte(); err != nil {
    167 			if err != io.EOF || i == 0 {
    168 				return
    169 			}
    170 			err = nil
    171 			break // i > 0
    172 		}
    173 		if ch < '0' || '9' < ch {
    174 			if i == 0 {
    175 				r.UnreadByte()
    176 				err = fmt.Errorf("invalid exponent (missing digits)")
    177 				return
    178 			}
    179 			break // i > 0
    180 		}
    181 		digits = append(digits, byte(ch))
    182 	}
    183 	// i > 0 => we have at least one digit
    184 
    185 	exp, err = strconv.ParseInt(string(digits), 10, 64)
    186 	return
    187 }
    188 
    189 // String returns a string representation of x in the form "a/b" (even if b == 1).
    190 func (x *Rat) String() string {
    191 	s := "/1"
    192 	if len(x.b.abs) != 0 {
    193 		s = "/" + x.b.abs.decimalString()
    194 	}
    195 	return x.a.String() + s
    196 }
    197 
    198 // RatString returns a string representation of x in the form "a/b" if b != 1,
    199 // and in the form "a" if b == 1.
    200 func (x *Rat) RatString() string {
    201 	if x.IsInt() {
    202 		return x.a.String()
    203 	}
    204 	return x.String()
    205 }
    206 
    207 // FloatString returns a string representation of x in decimal form with prec
    208 // digits of precision after the decimal point and the last digit rounded.
    209 func (x *Rat) FloatString(prec int) string {
    210 	if x.IsInt() {
    211 		s := x.a.String()
    212 		if prec > 0 {
    213 			s += "." + strings.Repeat("0", prec)
    214 		}
    215 		return s
    216 	}
    217 	// x.b.abs != 0
    218 
    219 	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
    220 
    221 	p := natOne
    222 	if prec > 0 {
    223 		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
    224 	}
    225 
    226 	r = r.mul(r, p)
    227 	r, r2 := r.div(nat(nil), r, x.b.abs)
    228 
    229 	// see if we need to round up
    230 	r2 = r2.add(r2, r2)
    231 	if x.b.abs.cmp(r2) <= 0 {
    232 		r = r.add(r, natOne)
    233 		if r.cmp(p) >= 0 {
    234 			q = nat(nil).add(q, natOne)
    235 			r = nat(nil).sub(r, p)
    236 		}
    237 	}
    238 
    239 	s := q.decimalString()
    240 	if x.a.neg {
    241 		s = "-" + s
    242 	}
    243 
    244 	if prec > 0 {
    245 		rs := r.decimalString()
    246 		leadingZeros := prec - len(rs)
    247 		s += "." + strings.Repeat("0", leadingZeros) + rs
    248 	}
    249 
    250 	return s
    251 }
    252