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