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