github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/big/ratconv.go (about) 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. The last digit is rounded to 209 // nearest, with halves rounded away from zero. 210 func (x *Rat) FloatString(prec int) string { 211 if x.IsInt() { 212 s := x.a.String() 213 if prec > 0 { 214 s += "." + strings.Repeat("0", prec) 215 } 216 return s 217 } 218 // x.b.abs != 0 219 220 q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs) 221 222 p := natOne 223 if prec > 0 { 224 p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil) 225 } 226 227 r = r.mul(r, p) 228 r, r2 := r.div(nat(nil), r, x.b.abs) 229 230 // see if we need to round up 231 r2 = r2.add(r2, r2) 232 if x.b.abs.cmp(r2) <= 0 { 233 r = r.add(r, natOne) 234 if r.cmp(p) >= 0 { 235 q = nat(nil).add(q, natOne) 236 r = nat(nil).sub(r, p) 237 } 238 } 239 240 s := q.decimalString() 241 if x.a.neg { 242 s = "-" + s 243 } 244 245 if prec > 0 { 246 rs := r.decimalString() 247 leadingZeros := prec - len(rs) 248 s += "." + strings.Repeat("0", leadingZeros) + rs 249 } 250 251 return s 252 }