summaryrefslogtreecommitdiff
path: root/src/pkg/exp/bignum/rational.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/bignum/rational.go')
-rw-r--r--src/pkg/exp/bignum/rational.go205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/pkg/exp/bignum/rational.go b/src/pkg/exp/bignum/rational.go
new file mode 100644
index 000000000..378585e5f
--- /dev/null
+++ b/src/pkg/exp/bignum/rational.go
@@ -0,0 +1,205 @@
+// Copyright 2009 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.
+
+// Rational numbers
+
+package bignum
+
+import "fmt"
+
+
+// Rational represents a quotient a/b of arbitrary precision.
+//
+type Rational struct {
+ a *Integer // numerator
+ b Natural // denominator
+}
+
+
+// MakeRat makes a rational number given a numerator a and a denominator b.
+//
+func MakeRat(a *Integer, b Natural) *Rational {
+ f := a.mant.Gcd(b) // f > 0
+ if f.Cmp(Nat(1)) != 0 {
+ a = MakeInt(a.sign, a.mant.Div(f))
+ b = b.Div(f)
+ }
+ return &Rational{a, b}
+}
+
+
+// Rat creates a small rational number with value a0/b0.
+//
+func Rat(a0 int64, b0 int64) *Rational {
+ a, b := Int(a0), Int(b0)
+ if b.sign {
+ a = a.Neg()
+ }
+ return MakeRat(a, b.mant)
+}
+
+
+// Value returns the numerator and denominator of x.
+//
+func (x *Rational) Value() (numerator *Integer, denominator Natural) {
+ return x.a, x.b
+}
+
+
+// Predicates
+
+// IsZero returns true iff x == 0.
+//
+func (x *Rational) IsZero() bool { return x.a.IsZero() }
+
+
+// IsNeg returns true iff x < 0.
+//
+func (x *Rational) IsNeg() bool { return x.a.IsNeg() }
+
+
+// IsPos returns true iff x > 0.
+//
+func (x *Rational) IsPos() bool { return x.a.IsPos() }
+
+
+// IsInt returns true iff x can be written with a denominator 1
+// in the form x == x'/1; i.e., if x is an integer value.
+//
+func (x *Rational) IsInt() bool { return x.b.Cmp(Nat(1)) == 0 }
+
+
+// Operations
+
+// Neg returns the negated value of x.
+//
+func (x *Rational) Neg() *Rational { return MakeRat(x.a.Neg(), x.b) }
+
+
+// Add returns the sum x + y.
+//
+func (x *Rational) Add(y *Rational) *Rational {
+ return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b))
+}
+
+
+// Sub returns the difference x - y.
+//
+func (x *Rational) Sub(y *Rational) *Rational {
+ return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b))
+}
+
+
+// Mul returns the product x * y.
+//
+func (x *Rational) Mul(y *Rational) *Rational { return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b)) }
+
+
+// Quo returns the quotient x / y for y != 0.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+func (x *Rational) Quo(y *Rational) *Rational {
+ a := x.a.MulNat(y.b)
+ b := y.a.MulNat(x.b)
+ if b.IsNeg() {
+ a = a.Neg()
+ }
+ return MakeRat(a, b.mant)
+}
+
+
+// Cmp compares x and y. The result is an int value
+//
+// < 0 if x < y
+// == 0 if x == y
+// > 0 if x > y
+//
+func (x *Rational) Cmp(y *Rational) int { return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b)) }
+
+
+// ToString converts x to a string for a given base, with 2 <= base <= 16.
+// The string representation is of the form "n" if x is an integer; otherwise
+// it is of form "n/d".
+//
+func (x *Rational) ToString(base uint) string {
+ s := x.a.ToString(base)
+ if !x.IsInt() {
+ s += "/" + x.b.ToString(base)
+ }
+ return s
+}
+
+
+// String converts x to its decimal string representation.
+// x.String() is the same as x.ToString(10).
+//
+func (x *Rational) String() string { return x.ToString(10) }
+
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
+//
+func (x *Rational) Format(h fmt.State, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))) }
+
+
+// RatFromString returns the rational number corresponding to the
+// longest possible prefix of s representing a rational number in a
+// given conversion base, the actual conversion base used, and the
+// prefix length. The syntax of a rational number is:
+//
+// rational = mantissa [exponent] .
+// mantissa = integer ('/' natural | '.' natural) .
+// exponent = ('e'|'E') integer .
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base for the mantissa. A prefix of ``0x'' or ``0X'' selects
+// base 16; the ``0'' prefix selects base 8. Otherwise the selected base is 10.
+// If the mantissa is represented via a division, both the numerator and
+// denominator may have different base prefixes; in that case the base of
+// of the numerator is returned. If the mantissa contains a decimal point,
+// the base for the fractional part is the same as for the part before the
+// decimal point and the fractional part does not accept a base prefix.
+// The base for the exponent is always 10.
+//
+func RatFromString(s string, base uint) (*Rational, uint, int) {
+ // read numerator
+ a, abase, alen := IntFromString(s, base)
+ b := Nat(1)
+
+ // read denominator or fraction, if any
+ var blen int
+ if alen < len(s) {
+ ch := s[alen]
+ if ch == '/' {
+ alen++
+ b, base, blen = NatFromString(s[alen:], base)
+ } else if ch == '.' {
+ alen++
+ b, base, blen = NatFromString(s[alen:], abase)
+ assert(base == abase)
+ f := Nat(uint64(base)).Pow(uint(blen))
+ a = MakeInt(a.sign, a.mant.Mul(f).Add(b))
+ b = f
+ }
+ }
+
+ // read exponent, if any
+ rlen := alen + blen
+ if rlen < len(s) {
+ ch := s[rlen]
+ if ch == 'e' || ch == 'E' {
+ rlen++
+ e, _, elen := IntFromString(s[rlen:], 10)
+ rlen += elen
+ m := Nat(10).Pow(uint(e.mant.Value()))
+ if e.sign {
+ b = b.Mul(m)
+ } else {
+ a = a.MulNat(m)
+ }
+ }
+ }
+
+ return MakeRat(a, b), base, rlen
+}