github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/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 (possibly signed) fraction "a/b", or as a 42 // floating-point number optionally followed by an exponent. 43 // If a fraction is provided, both the dividend and the divisor may be a 44 // decimal integer or independently use a prefix of ``0b'', ``0'' or ``0o'', 45 // or ``0x'' (or their upper-case variants) to denote a binary, octal, or 46 // hexadecimal integer, respectively. The divisor may not be signed. 47 // If a floating-point number is provided, it may be in decimal form or 48 // use any of the same prefixes as above but for ``0'' to denote a non-decimal 49 // mantissa. A leading ``0'' is considered a decimal leading 0; it does not 50 // indicate octal representation in this case. 51 // An optional base-10 ``e'' or base-2 ``p'' (or their upper-case variants) 52 // exponent may be provided as well, except for hexadecimal floats which 53 // only accept an (optional) ``p'' exponent (because an ``e'' or ``E'' cannot 54 // be distinguished from a mantissa digit). 55 // The entire string, not just a prefix, must be valid for success. If the 56 // operation failed, the value of z is undefined but the returned value is nil. 57 func (z *Rat) SetString(s string) (*Rat, bool) { 58 if len(s) == 0 { 59 return nil, false 60 } 61 // len(s) > 0 62 63 // parse fraction a/b, if any 64 if sep := strings.Index(s, "/"); sep >= 0 { 65 if _, ok := z.a.SetString(s[:sep], 0); !ok { 66 return nil, false 67 } 68 r := strings.NewReader(s[sep+1:]) 69 var err error 70 if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil { 71 return nil, false 72 } 73 // entire string must have been consumed 74 if _, err = r.ReadByte(); err != io.EOF { 75 return nil, false 76 } 77 if len(z.b.abs) == 0 { 78 return nil, false 79 } 80 return z.norm(), true 81 } 82 83 // parse floating-point number 84 r := strings.NewReader(s) 85 86 // sign 87 neg, err := scanSign(r) 88 if err != nil { 89 return nil, false 90 } 91 92 // mantissa 93 var base int 94 var fcount int // fractional digit count; valid if <= 0 95 z.a.abs, base, fcount, err = z.a.abs.scan(r, 0, true) 96 if err != nil { 97 return nil, false 98 } 99 100 // exponent 101 var exp int64 102 var ebase int 103 exp, ebase, err = scanExponent(r, true, true) 104 if err != nil { 105 return nil, false 106 } 107 108 // there should be no unread characters left 109 if _, err = r.ReadByte(); err != io.EOF { 110 return nil, false 111 } 112 113 // special-case 0 (see also issue #16176) 114 if len(z.a.abs) == 0 { 115 return z, true 116 } 117 // len(z.a.abs) > 0 118 119 // The mantissa may have a radix point (fcount <= 0) and there 120 // may be a nonzero exponent exp. The radix point amounts to a 121 // division by base**(-fcount), which equals a multiplication by 122 // base**fcount. An exponent means multiplication by ebase**exp. 123 // Multiplications are commutative, so we can apply them in any 124 // order. We only have powers of 2 and 10, and we split powers 125 // of 10 into the product of the same powers of 2 and 5. This 126 // may reduce the size of shift/multiplication factors or 127 // divisors required to create the final fraction, depending 128 // on the actual floating-point value. 129 130 // determine binary or decimal exponent contribution of radix point 131 var exp2, exp5 int64 132 if fcount < 0 { 133 // The mantissa has a radix point ddd.dddd; and 134 // -fcount is the number of digits to the right 135 // of '.'. Adjust relevant exponent accordingly. 136 d := int64(fcount) 137 switch base { 138 case 10: 139 exp5 = d 140 fallthrough // 10**e == 5**e * 2**e 141 case 2: 142 exp2 = d 143 case 8: 144 exp2 = d * 3 // octal digits are 3 bits each 145 case 16: 146 exp2 = d * 4 // hexadecimal digits are 4 bits each 147 default: 148 panic("unexpected mantissa base") 149 } 150 // fcount consumed - not needed anymore 151 } 152 153 // take actual exponent into account 154 switch ebase { 155 case 10: 156 exp5 += exp 157 fallthrough // see fallthrough above 158 case 2: 159 exp2 += exp 160 default: 161 panic("unexpected exponent base") 162 } 163 // exp consumed - not needed anymore 164 165 // apply exp5 contributions 166 // (start with exp5 so the numbers to multiply are smaller) 167 if exp5 != 0 { 168 n := exp5 169 if n < 0 { 170 n = -n 171 } 172 pow5 := z.b.abs.expNN(natFive, nat(nil).setWord(Word(n)), nil) // use underlying array of z.b.abs 173 if exp5 > 0 { 174 z.a.abs = z.a.abs.mul(z.a.abs, pow5) 175 z.b.abs = z.b.abs.setWord(1) 176 } else { 177 z.b.abs = pow5 178 } 179 } else { 180 z.b.abs = z.b.abs.setWord(1) 181 } 182 183 // apply exp2 contributions 184 if exp2 > 0 { 185 if int64(uint(exp2)) != exp2 { 186 panic("exponent too large") 187 } 188 z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2)) 189 } else if exp2 < 0 { 190 if int64(uint(-exp2)) != -exp2 { 191 panic("exponent too large") 192 } 193 z.b.abs = z.b.abs.shl(z.b.abs, uint(-exp2)) 194 } 195 196 z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign 197 198 return z.norm(), true 199 } 200 201 // scanExponent scans the longest possible prefix of r representing a base 10 202 // (``e'', ``E'') or a base 2 (``p'', ``P'') exponent, if any. It returns the 203 // exponent, the exponent base (10 or 2), or a read or syntax error, if any. 204 // 205 // If sepOk is set, an underscore character ``_'' may appear between successive 206 // exponent digits; such underscores do not change the value of the exponent. 207 // Incorrect placement of underscores is reported as an error if there are no 208 // other errors. If sepOk is not set, underscores are not recognized and thus 209 // terminate scanning like any other character that is not a valid digit. 210 // 211 // exponent = ( "e" | "E" | "p" | "P" ) [ sign ] digits . 212 // sign = "+" | "-" . 213 // digits = digit { [ '_' ] digit } . 214 // digit = "0" ... "9" . 215 // 216 // A base 2 exponent is only permitted if base2ok is set. 217 func scanExponent(r io.ByteScanner, base2ok, sepOk bool) (exp int64, base int, err error) { 218 // one char look-ahead 219 ch, err := r.ReadByte() 220 if err != nil { 221 if err == io.EOF { 222 err = nil 223 } 224 return 0, 10, err 225 } 226 227 // exponent char 228 switch ch { 229 case 'e', 'E': 230 base = 10 231 case 'p', 'P': 232 if base2ok { 233 base = 2 234 break // ok 235 } 236 fallthrough // binary exponent not permitted 237 default: 238 r.UnreadByte() // ch does not belong to exponent anymore 239 return 0, 10, nil 240 } 241 242 // sign 243 var digits []byte 244 ch, err = r.ReadByte() 245 if err == nil && (ch == '+' || ch == '-') { 246 if ch == '-' { 247 digits = append(digits, '-') 248 } 249 ch, err = r.ReadByte() 250 } 251 252 // prev encodes the previously seen char: it is one 253 // of '_', '0' (a digit), or '.' (anything else). A 254 // valid separator '_' may only occur after a digit. 255 prev := '.' 256 invalSep := false 257 258 // exponent value 259 hasDigits := false 260 for err == nil { 261 if '0' <= ch && ch <= '9' { 262 digits = append(digits, ch) 263 prev = '0' 264 hasDigits = true 265 } else if ch == '_' && sepOk { 266 if prev != '0' { 267 invalSep = true 268 } 269 prev = '_' 270 } else { 271 r.UnreadByte() // ch does not belong to number anymore 272 break 273 } 274 ch, err = r.ReadByte() 275 } 276 277 if err == io.EOF { 278 err = nil 279 } 280 if err == nil && !hasDigits { 281 err = errNoDigits 282 } 283 if err == nil { 284 exp, err = strconv.ParseInt(string(digits), 10, 64) 285 } 286 // other errors take precedence over invalid separators 287 if err == nil && (invalSep || prev == '_') { 288 err = errInvalSep 289 } 290 291 return 292 } 293 294 // String returns a string representation of x in the form "a/b" (even if b == 1). 295 func (x *Rat) String() string { 296 return string(x.marshal()) 297 } 298 299 // marshal implements String returning a slice of bytes 300 func (x *Rat) marshal() []byte { 301 var buf []byte 302 buf = x.a.Append(buf, 10) 303 buf = append(buf, '/') 304 if len(x.b.abs) != 0 { 305 buf = x.b.Append(buf, 10) 306 } else { 307 buf = append(buf, '1') 308 } 309 return buf 310 } 311 312 // RatString returns a string representation of x in the form "a/b" if b != 1, 313 // and in the form "a" if b == 1. 314 func (x *Rat) RatString() string { 315 if x.IsInt() { 316 return x.a.String() 317 } 318 return x.String() 319 } 320 321 // FloatString returns a string representation of x in decimal form with prec 322 // digits of precision after the radix point. The last digit is rounded to 323 // nearest, with halves rounded away from zero. 324 func (x *Rat) FloatString(prec int) string { 325 var buf []byte 326 327 if x.IsInt() { 328 buf = x.a.Append(buf, 10) 329 if prec > 0 { 330 buf = append(buf, '.') 331 for i := prec; i > 0; i-- { 332 buf = append(buf, '0') 333 } 334 } 335 return string(buf) 336 } 337 // x.b.abs != 0 338 339 q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs) 340 341 p := natOne 342 if prec > 0 { 343 p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil) 344 } 345 346 r = r.mul(r, p) 347 r, r2 := r.div(nat(nil), r, x.b.abs) 348 349 // see if we need to round up 350 r2 = r2.add(r2, r2) 351 if x.b.abs.cmp(r2) <= 0 { 352 r = r.add(r, natOne) 353 if r.cmp(p) >= 0 { 354 q = nat(nil).add(q, natOne) 355 r = nat(nil).sub(r, p) 356 } 357 } 358 359 if x.a.neg { 360 buf = append(buf, '-') 361 } 362 buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0 363 364 if prec > 0 { 365 buf = append(buf, '.') 366 rs := r.utoa(10) 367 for i := prec - len(rs); i > 0; i-- { 368 buf = append(buf, '0') 369 } 370 buf = append(buf, rs...) 371 } 372 373 return string(buf) 374 }