Source File
ratconv.go
Belonging Package
math/big
// 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 (
)
func ratTok( rune) bool {
return strings.ContainsRune("+-/0123456789.eE", )
}
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 ( *Rat) ( fmt.ScanState, rune) error {
, := .Token(true, ratTok)
if != nil {
return
}
if !strings.ContainsRune("efgEFGv", ) {
return errors.New("Rat.Scan: invalid verb")
}
if , := .SetString(string()); ! {
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 ( *Rat) ( string) (*Rat, bool) {
if len() == 0 {
return nil, false
}
// len(s) > 0
// parse fraction a/b, if any
if := strings.Index(, "/"); >= 0 {
if , := .a.SetString([:], 0); ! {
return nil, false
}
:= strings.NewReader([+1:])
var error
if .b.abs, _, _, = .b.abs.scan(, 0, false); != nil {
return nil, false
}
// entire string must have been consumed
if _, = .ReadByte(); != io.EOF {
return nil, false
}
if len(.b.abs) == 0 {
return nil, false
}
return .norm(), true
}
// parse floating-point number
:= strings.NewReader()
// sign
, := scanSign()
if != nil {
return nil, false
}
// mantissa
var int
var int // fractional digit count; valid if <= 0
.a.abs, , , = .a.abs.scan(, 0, true)
if != nil {
return nil, false
}
// exponent
var int64
var int
, , = scanExponent(, true, true)
if != nil {
return nil, false
}
// there should be no unread characters left
if _, = .ReadByte(); != io.EOF {
return nil, false
}
// special-case 0 (see also issue #16176)
if len(.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 point
var , int64
if < 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 {
case 10:
=
fallthrough // 10**e == 5**e * 2**e
case 2:
=
case 8:
= * 3 // octal digits are 3 bits each
case 16:
= * 4 // hexadecimal digits are 4 bits each
default:
panic("unexpected mantissa base")
}
// fcount consumed - not needed anymore
}
// take actual exponent into account
switch {
case 10:
+=
fallthrough // see fallthrough above
case 2:
+=
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.
return nil, false
}
}
if > 1e6 {
return nil, false // avoid excessively large exponents
}
:= .b.abs.expNN(natFive, nat(nil).setWord(Word()), nil, false) // use underlying array of z.b.abs
if > 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 contributions
if < -1e7 || > 1e7 {
return nil, false // avoid excessively large exponents
}
if > 0 {
.a.abs = .a.abs.shl(.a.abs, uint())
} else if < 0 {
.b.abs = .b.abs.shl(.b.abs, uint(-))
}
.a.neg = && len(.a.abs) > 0 // 0 has no sign
return .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( io.ByteScanner, , bool) ( int64, int, error) {
// one char look-ahead
, := .ReadByte()
if != nil {
if == io.EOF {
= nil
}
return 0, 10,
}
// exponent char
switch {
case 'e', 'E':
= 10
case 'p', 'P':
if {
= 2
break // ok
}
fallthrough // binary exponent not permitted
default:
.UnreadByte() // ch does not belong to exponent anymore
return 0, 10, nil
}
// sign
var []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
:= false
for == nil {
if '0' <= && <= '9' {
= append(, )
= '0'
= true
} else if == '_' && {
if != '0' {
= true
}
= '_'
} else {
.UnreadByte() // ch does not belong to number anymore
break
}
, = .ReadByte()
}
if == io.EOF {
= nil
}
if == nil && ! {
= errNoDigits
}
if == nil {
, = strconv.ParseInt(string(), 10, 64)
}
// other errors take precedence over invalid separators
if == nil && ( || == '_') {
= errInvalSep
}
return
}
// String returns a string representation of x in the form "a/b" (even if b == 1).
func ( *Rat) () string {
return string(.marshal(nil))
}
// marshal implements [Rat.String] returning a slice of bytes.
// It appends the string representation of x in the form "a/b" (even if b == 1) to buf,
// and returns the extended buffer.
func ( *Rat) ( []byte) []byte {
= .a.Append(, 10)
= append(, '/')
if len(.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 []byte
if .IsInt() {
= .a.Append(, 10)
if > 0 {
= append(, '.')
for := ; > 0; -- {
= append(, '0')
}
}
return string()
}
// x.b.abs != 0
, := nat(nil).div(nat(nil), .a.abs, .b.abs)
:= natOne
if > 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 == 0
if > 0 {
= append(, '.')
:= .utoa(10)
for := - len(); > 0; -- {
= append(, '0')
}
= append(, ...)
}
return string()
}
// Note: FloatPrec (below) is in this file rather than rat.go because
// its results are relevant for decimal representation/printing.
// FloatPrec returns the number n of non-repeating digits immediately
// following the decimal point of the decimal representation of x.
// The boolean result indicates whether a decimal representation of x
// with that many fractional digits is exact or rounded.
//
// Examples:
//
// x n exact decimal representation n fractional digits
// 0 0 true 0
// 1 0 true 1
// 1/2 1 true 0.5
// 1/3 0 false 0 (0.333... rounded)
// 1/4 2 true 0.25
// 1/6 1 false 0.2 (0.166... rounded)
func ( *Rat) () ( int, bool) {
// Determine q and largest p2, p5 such that d = q·2^p2·5^p5.
// The results n, exact are:
//
// n = max(p2, p5)
// exact = q == 1
//
// For details see:
// https://en.wikipedia.org/wiki/Repeating_decimal#Reciprocals_of_integers_not_coprime_to_10
:= .Denom().abs // d >= 1
// Determine p2 by counting factors of 2.
// p2 corresponds to the trailing zero bits in d.
// Do this first to reduce q as much as possible.
var nat
:= .trailingZeroBits()
= .shr(, )
// Determine p5 by counting factors of 5.
// Build a table starting with an initial power of 5,
// and use repeated squaring until the factor doesn't
// divide q anymore. Then use the table to determine
// the power of 5 in q.
const = 13 // f == 5^fp
var []nat // tab[i] == (5^fp)^(2^i) == 5^(fp·2^i)
:= nat{1220703125} // == 5^fp (must fit into a uint32 Word)
var , nat // temporaries
for {
if _, = .div(, , ); len() != 0 {
break // f doesn't divide q evenly
}
= append(, )
= nat(nil).sqr() // nat(nil) to ensure a new f for each table entry
}
// Factor q using the table entries, if any.
// We start with the largest factor f = tab[len(tab)-1]
// that evenly divides q. It does so at most once because
// otherwise f·f would also divide q. That can't be true
// because f·f is the next higher table entry, contradicting
// how f was chosen in the first place.
// The same reasoning applies to the subsequent factors.
var uint
for := len() - 1; >= 0; -- {
if , = .div(, , []); len() == 0 {
+= * (1 << ) // tab[i] == 5^(fp·2^i)
= .set()
}
}
// If fp != 1, we may still have multiples of 5 left.
for {
if , = .div(, , natFive); len() != 0 {
break
}
++
= .set()
}
return int(max(, )), .cmp(natOne) == 0
}
The pages are generated with Golds v0.7.3. (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |