| // 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. |
| |
| // This file implements Newton-Raphson division and uses |
| // it as an additional test case for bignum. |
| // |
| // Division of x/y is achieved by computing r = 1/y to |
| // obtain the quotient q = x*r = x*(1/y) = x/y. The |
| // reciprocal r is the solution for f(x) = 1/x - y and |
| // the solution is approximated through iteration. The |
| // iteration does not require division. |
| |
| package bignum |
| |
| import "testing" |
| |
| |
| // An fpNat is a Natural scaled by a power of two |
| // (an unsigned floating point representation). The |
| // value of an fpNat x is x.m * 2^x.e . |
| // |
| type fpNat struct { |
| m Natural |
| e int |
| } |
| |
| |
| // sub computes x - y. |
| func (x fpNat) sub(y fpNat) fpNat { |
| switch d := x.e - y.e; { |
| case d < 0: |
| return fpNat{x.m.Sub(y.m.Shl(uint(-d))), x.e} |
| case d > 0: |
| return fpNat{x.m.Shl(uint(d)).Sub(y.m), y.e} |
| } |
| return fpNat{x.m.Sub(y.m), x.e} |
| } |
| |
| |
| // mul2 computes x*2. |
| func (x fpNat) mul2() fpNat { return fpNat{x.m, x.e + 1} } |
| |
| |
| // mul computes x*y. |
| func (x fpNat) mul(y fpNat) fpNat { return fpNat{x.m.Mul(y.m), x.e + y.e} } |
| |
| |
| // mant computes the (possibly truncated) Natural representation |
| // of an fpNat x. |
| // |
| func (x fpNat) mant() Natural { |
| switch { |
| case x.e > 0: |
| return x.m.Shl(uint(x.e)) |
| case x.e < 0: |
| return x.m.Shr(uint(-x.e)) |
| } |
| return x.m |
| } |
| |
| |
| // nrDivEst computes an estimate of the quotient q = x0/y0 and returns q. |
| // q may be too small (usually by 1). |
| // |
| func nrDivEst(x0, y0 Natural) Natural { |
| if y0.IsZero() { |
| panic("division by zero") |
| return nil |
| } |
| // y0 > 0 |
| |
| if y0.Cmp(Nat(1)) == 0 { |
| return x0 |
| } |
| // y0 > 1 |
| |
| switch d := x0.Cmp(y0); { |
| case d < 0: |
| return Nat(0) |
| case d == 0: |
| return Nat(1) |
| } |
| // x0 > y0 > 1 |
| |
| // Determine maximum result length. |
| maxLen := int(x0.Log2() - y0.Log2() + 1) |
| |
| // In the following, each number x is represented |
| // as a mantissa x.m and an exponent x.e such that |
| // x = xm * 2^x.e. |
| x := fpNat{x0, 0} |
| y := fpNat{y0, 0} |
| |
| // Determine a scale factor f = 2^e such that |
| // 0.5 <= y/f == y*(2^-e) < 1.0 |
| // and scale y accordingly. |
| e := int(y.m.Log2()) + 1 |
| y.e -= e |
| |
| // t1 |
| var c = 2.9142 |
| const n = 14 |
| t1 := fpNat{Nat(uint64(c * (1 << n))), -n} |
| |
| // Compute initial value r0 for the reciprocal of y/f. |
| // r0 = t1 - 2*y |
| r := t1.sub(y.mul2()) |
| two := fpNat{Nat(2), 0} |
| |
| // Newton-Raphson iteration |
| p := Nat(0) |
| for i := 0; ; i++ { |
| // check if we are done |
| // TODO: Need to come up with a better test here |
| // as it will reduce computation time significantly. |
| // q = x*r/f |
| q := x.mul(r) |
| q.e -= e |
| res := q.mant() |
| if res.Cmp(p) == 0 { |
| return res |
| } |
| p = res |
| |
| // r' = r*(2 - y*r) |
| r = r.mul(two.sub(y.mul(r))) |
| |
| // reduce mantissa size |
| // TODO: Find smaller bound as it will reduce |
| // computation time massively. |
| d := int(r.m.Log2()+1) - maxLen |
| if d > 0 { |
| r = fpNat{r.m.Shr(uint(d)), r.e + d} |
| } |
| } |
| |
| panic("unreachable") |
| return nil |
| } |
| |
| |
| func nrdiv(x, y Natural) (q, r Natural) { |
| q = nrDivEst(x, y) |
| r = x.Sub(y.Mul(q)) |
| // if r is too large, correct q and r |
| // (usually one iteration) |
| for r.Cmp(y) >= 0 { |
| q = q.Add(Nat(1)) |
| r = r.Sub(y) |
| } |
| return |
| } |
| |
| |
| func div(t *testing.T, x, y Natural) { |
| q, r := nrdiv(x, y) |
| qx, rx := x.DivMod(y) |
| if q.Cmp(qx) != 0 { |
| t.Errorf("x = %s, y = %s, got q = %s, want q = %s", x, y, q, qx) |
| } |
| if r.Cmp(rx) != 0 { |
| t.Errorf("x = %s, y = %s, got r = %s, want r = %s", x, y, r, rx) |
| } |
| } |
| |
| |
| func idiv(t *testing.T, x0, y0 uint64) { div(t, Nat(x0), Nat(y0)) } |
| |
| |
| func TestNRDiv(t *testing.T) { |
| idiv(t, 17, 18) |
| idiv(t, 17, 17) |
| idiv(t, 17, 1) |
| idiv(t, 17, 16) |
| idiv(t, 17, 10) |
| idiv(t, 17, 9) |
| idiv(t, 17, 8) |
| idiv(t, 17, 5) |
| idiv(t, 17, 3) |
| idiv(t, 1025, 512) |
| idiv(t, 7489595, 2) |
| idiv(t, 5404679459, 78495) |
| idiv(t, 7484890589595, 7484890589594) |
| div(t, Fact(100), Fact(91)) |
| div(t, Fact(1000), Fact(991)) |
| //div(t, Fact(10000), Fact(9991)); // takes too long - disabled for now |
| } |