| // 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). |
| // 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 |
| } |
| 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 > 0 { |
| if int64(uint(exp2)) != exp2 { |
| panic("exponent too large") |
| } |
| z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2)) |
| } else if exp2 < 0 { |
| if int64(uint(-exp2)) != -exp2 { |
| panic("exponent too large") |
| } |
| 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) |
| } |