// 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 bigimport ()func ( rune) bool {returnstrings.ContainsRune("+-/0123456789.eE", )}varratZeroRatvar _ 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 ( *Rat) ( fmt.ScanState, rune) error { , := .Token(true, ratTok)if != nil {return }if !strings.ContainsRune("efgEFGv", ) {returnerrors.New("Rat.Scan: invalid verb") }if , := .SetString(string()); ! {returnerrors.New("Rat.Scan: invalid syntax") }returnnil}// 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 ( *Rat) ( string) (*Rat, bool) {iflen() == 0 {returnnil, false }// len(s) > 0// parse fraction a/b, if anyif := strings.Index(, "/"); >= 0 {if , := .a.SetString([:], 0); ! {returnnil, false } := strings.NewReader([+1:])varerrorif .b.abs, _, _, = .b.abs.scan(, 0, false); != nil {returnnil, false }// entire string must have been consumedif _, = .ReadByte(); != io.EOF {returnnil, false }iflen(.b.abs) == 0 {returnnil, false }return .norm(), true }// parse floating-point number := strings.NewReader()// sign , := scanSign()if != nil {returnnil, false }// mantissavarintvarint// fractional digit count; valid if <= 0 .a.abs, , , = .a.abs.scan(, 0, true)if != nil {returnnil, false }// exponentvarint64varint , , = scanExponent(, true, true)if != nil {returnnil, false }// there should be no unread characters leftif _, = .ReadByte(); != io.EOF {returnnil, false }// special-case 0 (see also issue #16176)iflen(.a.abs) == 0 {return .norm(), 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 pointvar , int64if < 0 {// The mantissa has a radix point ddd.dddd; and // -fcount is the number of digits to the right // of '.'. Adjust relevant exponent accordingly. := int64()switch {case10: = fallthrough// 10**e == 5**e * 2**ecase2: = case8: = * 3// octal digits are 3 bits eachcase16: = * 4// hexadecimal digits are 4 bits eachdefault:panic("unexpected mantissa base") }// fcount consumed - not needed anymore }// take actual exponent into accountswitch {case10: += fallthrough// see fallthrough abovecase2: += default:panic("unexpected exponent base") }// exp consumed - not needed anymore// apply exp5 contributions // (start with exp5 so the numbers to multiply are smaller)if != 0 { := if < 0 { = -if < 0 {// This can occur if -n overflows. -(-1 << 63) would become // -1 << 63, which is still negative.returnnil, false } }if > 1e6 {returnnil, false// avoid excessively large exponents } := .b.abs.expNN(natFive, nat(nil).setWord(Word()), nil, false) // use underlying array of z.b.absif > 0 { .a.abs = .a.abs.mul(.a.abs, ) .b.abs = .b.abs.setWord(1) } else { .b.abs = } } else { .b.abs = .b.abs.setWord(1) }// apply exp2 contributionsif < -1e7 || > 1e7 {returnnil, false// avoid excessively large exponents }if > 0 { .a.abs = .a.abs.shl(.a.abs, uint()) } elseif < 0 { .b.abs = .b.abs.shl(.b.abs, uint(-)) } .a.neg = && len(.a.abs) > 0// 0 has no signreturn .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 ( io.ByteScanner, , bool) ( int64, int, error) {// one char look-ahead , := .ReadByte()if != nil {if == io.EOF { = nil }return0, 10, }// exponent charswitch {case'e', 'E': = 10case'p', 'P':if { = 2break// ok }fallthrough// binary exponent not permitteddefault: .UnreadByte() // ch does not belong to exponent anymorereturn0, 10, nil }// signvar []byte , = .ReadByte()if == nil && ( == '+' || == '-') {if == '-' { = append(, '-') } , = .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. := '.' := false// exponent value := falsefor == nil {if'0' <= && <= '9' { = append(, ) = '0' = true } elseif == '_' && {if != '0' { = true } = '_' } else { .UnreadByte() // ch does not belong to number anymorebreak } , = .ReadByte() }if == io.EOF { = nil }if == nil && ! { = errNoDigits }if == nil { , = strconv.ParseInt(string(), 10, 64) }// other errors take precedence over invalid separatorsif == nil && ( || == '_') { = errInvalSep }return}// String returns a string representation of x in the form "a/b" (even if b == 1).func ( *Rat) () string {returnstring(.marshal())}// marshal implements String returning a slice of bytesfunc ( *Rat) () []byte {var []byte = .a.Append(, 10) = append(, '/')iflen(.b.abs) != 0 { = .b.Append(, 10) } else { = append(, '1') }return}// RatString returns a string representation of x in the form "a/b" if b != 1,// and in the form "a" if b == 1.func ( *Rat) () string {if .IsInt() {return .a.String() }return .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 ( *Rat) ( int) string {var []byteif .IsInt() { = .a.Append(, 10)if > 0 { = append(, '.')for := ; > 0; -- { = append(, '0') } }returnstring() }// x.b.abs != 0 , := nat(nil).div(nat(nil), .a.abs, .b.abs) := natOneif > 0 { = nat(nil).expNN(natTen, nat(nil).setUint64(uint64()), nil, false) } = .mul(, ) , := .div(nat(nil), , .b.abs)// see if we need to round up = .add(, )if .b.abs.cmp() <= 0 { = .add(, natOne)if .cmp() >= 0 { = nat(nil).add(, natOne) = nat(nil).sub(, ) } }if .a.neg { = append(, '-') } = append(, .utoa(10)...) // itoa ignores sign if q == 0if > 0 { = append(, '.') := .utoa(10)for := - len(); > 0; -- { = append(, '0') } = append(, ...) }returnstring()}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.