Commit 841a32dd authored by Evan Shaw's avatar Evan Shaw Committed by Robert Griesemer

big: Create type nat

Changed most of the functions in nat.go to methods on nat.

R=gri
CC=golang-dev
https://golang.org/cl/976041
parent 5cd8c830
...@@ -52,7 +52,7 @@ func TestFunWW(t *testing.T) { ...@@ -52,7 +52,7 @@ func TestFunWW(t *testing.T) {
} }
func addr(x []Word) *Word { func addr(x nat) *Word {
if len(x) == 0 { if len(x) == 0 {
return nil return nil
} }
...@@ -62,26 +62,26 @@ func addr(x []Word) *Word { ...@@ -62,26 +62,26 @@ func addr(x []Word) *Word {
type funVV func(z, x, y *Word, n int) (c Word) type funVV func(z, x, y *Word, n int) (c Word)
type argVV struct { type argVV struct {
z, x, y []Word z, x, y nat
c Word c Word
} }
var sumVV = []argVV{ var sumVV = []argVV{
argVV{}, argVV{},
argVV{[]Word{0}, []Word{0}, []Word{0}, 0}, argVV{nat{0}, nat{0}, nat{0}, 0},
argVV{[]Word{1}, []Word{1}, []Word{0}, 0}, argVV{nat{1}, nat{1}, nat{0}, 0},
argVV{[]Word{0}, []Word{_M}, []Word{1}, 1}, argVV{nat{0}, nat{_M}, nat{1}, 1},
argVV{[]Word{80235}, []Word{12345}, []Word{67890}, 0}, argVV{nat{80235}, nat{12345}, nat{67890}, 0},
argVV{[]Word{_M - 1}, []Word{_M}, []Word{_M}, 1}, argVV{nat{_M - 1}, nat{_M}, nat{_M}, 1},
argVV{[]Word{0, 0, 0, 0}, []Word{_M, _M, _M, _M}, []Word{1, 0, 0, 0}, 1}, argVV{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
argVV{[]Word{0, 0, 0, _M}, []Word{_M, _M, _M, _M - 1}, []Word{1, 0, 0, 0}, 0}, argVV{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
argVV{[]Word{0, 0, 0, 0}, []Word{_M, 0, _M, 0}, []Word{1, _M, 0, _M}, 1}, argVV{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
} }
func testFunVV(t *testing.T, msg string, f funVV, a argVV) { func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
n := len(a.z) n := len(a.z)
z := make([]Word, n) z := make(nat, n)
c := f(addr(z), addr(a.x), addr(a.y), n) c := f(addr(z), addr(a.x), addr(a.y), n)
for i, zi := range z { for i, zi := range z {
if zi != a.z[i] { if zi != a.z[i] {
...@@ -118,39 +118,39 @@ func TestFunVV(t *testing.T) { ...@@ -118,39 +118,39 @@ func TestFunVV(t *testing.T) {
type funVW func(z, x *Word, y Word, n int) (c Word) type funVW func(z, x *Word, y Word, n int) (c Word)
type argVW struct { type argVW struct {
z, x []Word z, x nat
y Word y Word
c Word c Word
} }
var sumVW = []argVW{ var sumVW = []argVW{
argVW{}, argVW{},
argVW{[]Word{0}, []Word{0}, 0, 0}, argVW{nat{0}, nat{0}, 0, 0},
argVW{[]Word{1}, []Word{0}, 1, 0}, argVW{nat{1}, nat{0}, 1, 0},
argVW{[]Word{1}, []Word{1}, 0, 0}, argVW{nat{1}, nat{1}, 0, 0},
argVW{[]Word{0}, []Word{_M}, 1, 1}, argVW{nat{0}, nat{_M}, 1, 1},
argVW{[]Word{0, 0, 0, 0}, []Word{_M, _M, _M, _M}, 1, 1}, argVW{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
} }
var prodVW = []argVW{ var prodVW = []argVW{
argVW{}, argVW{},
argVW{[]Word{0}, []Word{0}, 0, 0}, argVW{nat{0}, nat{0}, 0, 0},
argVW{[]Word{0}, []Word{_M}, 0, 0}, argVW{nat{0}, nat{_M}, 0, 0},
argVW{[]Word{0}, []Word{0}, _M, 0}, argVW{nat{0}, nat{0}, _M, 0},
argVW{[]Word{1}, []Word{1}, 1, 0}, argVW{nat{1}, nat{1}, 1, 0},
argVW{[]Word{22793}, []Word{991}, 23, 0}, argVW{nat{22793}, nat{991}, 23, 0},
argVW{[]Word{0, 0, 0, 22793}, []Word{0, 0, 0, 991}, 23, 0}, argVW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
argVW{[]Word{0, 0, 0, 0}, []Word{7893475, 7395495, 798547395, 68943}, 0, 0}, argVW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
argVW{[]Word{0, 0, 0, 0}, []Word{0, 0, 0, 0}, 894375984, 0}, argVW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
argVW{[]Word{_M << 1 & _M}, []Word{_M}, 1 << 1, _M >> (_W - 1)}, argVW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
argVW{[]Word{_M << 7 & _M}, []Word{_M}, 1 << 7, _M >> (_W - 7)}, argVW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
argVW{[]Word{_M << 7 & _M, _M, _M, _M}, []Word{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)}, argVW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
} }
func testFunVW(t *testing.T, msg string, f funVW, a argVW) { func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
n := len(a.z) n := len(a.z)
z := make([]Word, n) z := make(nat, n)
c := f(addr(z), addr(a.x), a.y, n) c := f(addr(z), addr(a.x), a.y, n)
for i, zi := range z { for i, zi := range z {
if zi != a.z[i] { if zi != a.z[i] {
...@@ -179,41 +179,41 @@ func TestFunVW(t *testing.T) { ...@@ -179,41 +179,41 @@ func TestFunVW(t *testing.T) {
type funVWW func(z, x *Word, y, r Word, n int) (c Word) type funVWW func(z, x *Word, y, r Word, n int) (c Word)
type argVWW struct { type argVWW struct {
z, x []Word z, x nat
y, r Word y, r Word
c Word c Word
} }
var prodVWW = []argVWW{ var prodVWW = []argVWW{
argVWW{}, argVWW{},
argVWW{[]Word{0}, []Word{0}, 0, 0, 0}, argVWW{nat{0}, nat{0}, 0, 0, 0},
argVWW{[]Word{991}, []Word{0}, 0, 991, 0}, argVWW{nat{991}, nat{0}, 0, 991, 0},
argVWW{[]Word{0}, []Word{_M}, 0, 0, 0}, argVWW{nat{0}, nat{_M}, 0, 0, 0},
argVWW{[]Word{991}, []Word{_M}, 0, 991, 0}, argVWW{nat{991}, nat{_M}, 0, 991, 0},
argVWW{[]Word{0}, []Word{0}, _M, 0, 0}, argVWW{nat{0}, nat{0}, _M, 0, 0},
argVWW{[]Word{991}, []Word{0}, _M, 991, 0}, argVWW{nat{991}, nat{0}, _M, 991, 0},
argVWW{[]Word{1}, []Word{1}, 1, 0, 0}, argVWW{nat{1}, nat{1}, 1, 0, 0},
argVWW{[]Word{992}, []Word{1}, 1, 991, 0}, argVWW{nat{992}, nat{1}, 1, 991, 0},
argVWW{[]Word{22793}, []Word{991}, 23, 0, 0}, argVWW{nat{22793}, nat{991}, 23, 0, 0},
argVWW{[]Word{22800}, []Word{991}, 23, 7, 0}, argVWW{nat{22800}, nat{991}, 23, 7, 0},
argVWW{[]Word{0, 0, 0, 22793}, []Word{0, 0, 0, 991}, 23, 0, 0}, argVWW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
argVWW{[]Word{7, 0, 0, 22793}, []Word{0, 0, 0, 991}, 23, 7, 0}, argVWW{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
argVWW{[]Word{0, 0, 0, 0}, []Word{7893475, 7395495, 798547395, 68943}, 0, 0, 0}, argVWW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
argVWW{[]Word{991, 0, 0, 0}, []Word{7893475, 7395495, 798547395, 68943}, 0, 991, 0}, argVWW{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
argVWW{[]Word{0, 0, 0, 0}, []Word{0, 0, 0, 0}, 894375984, 0, 0}, argVWW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
argVWW{[]Word{991, 0, 0, 0}, []Word{0, 0, 0, 0}, 894375984, 991, 0}, argVWW{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
argVWW{[]Word{_M << 1 & _M}, []Word{_M}, 1 << 1, 0, _M >> (_W - 1)}, argVWW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
argVWW{[]Word{_M<<1&_M + 1}, []Word{_M}, 1 << 1, 1, _M >> (_W - 1)}, argVWW{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
argVWW{[]Word{_M << 7 & _M}, []Word{_M}, 1 << 7, 0, _M >> (_W - 7)}, argVWW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
argVWW{[]Word{_M<<7&_M + 1<<6}, []Word{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, argVWW{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
argVWW{[]Word{_M << 7 & _M, _M, _M, _M}, []Word{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)}, argVWW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
argVWW{[]Word{_M<<7&_M + 1<<6, _M, _M, _M}, []Word{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, argVWW{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
} }
func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) { func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
n := len(a.z) n := len(a.z)
z := make([]Word, n) z := make(nat, n)
c := f(addr(z), addr(a.x), a.y, a.r, n) c := f(addr(z), addr(a.x), a.y, a.r, n)
for i, zi := range z { for i, zi := range z {
if zi != a.z[i] { if zi != a.z[i] {
...@@ -232,16 +232,16 @@ func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) { ...@@ -232,16 +232,16 @@ func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
type funWVW func(z *Word, xn Word, x *Word, y Word, n int) (r Word) type funWVW func(z *Word, xn Word, x *Word, y Word, n int) (r Word)
type argWVW struct { type argWVW struct {
z []Word z nat
xn Word xn Word
x []Word x nat
y Word y Word
r Word r Word
} }
func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) { func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
n := len(a.z) n := len(a.z)
z := make([]Word, n) z := make(nat, n)
r := f(addr(z), a.xn, addr(a.x), a.y, n) r := f(addr(z), a.xn, addr(a.x), a.y, n)
for i, zi := range z { for i, zi := range z {
if zi != a.z[i] { if zi != a.z[i] {
......
...@@ -10,7 +10,7 @@ package big ...@@ -10,7 +10,7 @@ package big
// The zero value for an Int represents the value 0. // The zero value for an Int represents the value 0.
type Int struct { type Int struct {
neg bool // sign neg bool // sign
abs []Word // absolute value of the integer abs nat // absolute value of the integer
} }
...@@ -21,7 +21,7 @@ func (z *Int) New(x int64) *Int { ...@@ -21,7 +21,7 @@ func (z *Int) New(x int64) *Int {
z.neg = true z.neg = true
x = -x x = -x
} }
z.abs = newN(z.abs, uint64(x)) z.abs = z.abs.new(uint64(x))
return z return z
} }
...@@ -33,7 +33,7 @@ func NewInt(x int64) *Int { return new(Int).New(x) } ...@@ -33,7 +33,7 @@ func NewInt(x int64) *Int { return new(Int).New(x) }
// Set sets z to x. // Set sets z to x.
func (z *Int) Set(x *Int) *Int { func (z *Int) Set(x *Int) *Int {
z.neg = x.neg z.neg = x.neg
z.abs = setN(z.abs, x.abs) z.abs = z.abs.set(x.abs)
return z return z
} }
...@@ -44,16 +44,16 @@ func (z *Int) Add(x, y *Int) *Int { ...@@ -44,16 +44,16 @@ func (z *Int) Add(x, y *Int) *Int {
// x + y == x + y // x + y == x + y
// (-x) + (-y) == -(x + y) // (-x) + (-y) == -(x + y)
z.neg = x.neg z.neg = x.neg
z.abs = addNN(z.abs, x.abs, y.abs) z.abs = z.abs.add(x.abs, y.abs)
} else { } else {
// x + (-y) == x - y == -(y - x) // x + (-y) == x - y == -(y - x)
// (-x) + y == y - x == -(x - y) // (-x) + y == y - x == -(x - y)
if cmpNN(x.abs, y.abs) >= 0 { if x.abs.cmp(y.abs) >= 0 {
z.neg = x.neg z.neg = x.neg
z.abs = subNN(z.abs, x.abs, y.abs) z.abs = z.abs.sub(x.abs, y.abs)
} else { } else {
z.neg = !x.neg z.neg = !x.neg
z.abs = subNN(z.abs, y.abs, x.abs) z.abs = z.abs.sub(y.abs, x.abs)
} }
} }
if len(z.abs) == 0 { if len(z.abs) == 0 {
...@@ -69,16 +69,16 @@ func (z *Int) Sub(x, y *Int) *Int { ...@@ -69,16 +69,16 @@ func (z *Int) Sub(x, y *Int) *Int {
// x - (-y) == x + y // x - (-y) == x + y
// (-x) - y == -(x + y) // (-x) - y == -(x + y)
z.neg = x.neg z.neg = x.neg
z.abs = addNN(z.abs, x.abs, y.abs) z.abs = z.abs.add(x.abs, y.abs)
} else { } else {
// x - y == x - y == -(y - x) // x - y == x - y == -(y - x)
// (-x) - (-y) == y - x == -(x - y) // (-x) - (-y) == y - x == -(x - y)
if cmpNN(x.abs, y.abs) >= 0 { if x.abs.cmp(y.abs) >= 0 {
z.neg = x.neg z.neg = x.neg
z.abs = subNN(z.abs, x.abs, y.abs) z.abs = z.abs.sub(x.abs, y.abs)
} else { } else {
z.neg = !x.neg z.neg = !x.neg
z.abs = subNN(z.abs, y.abs, x.abs) z.abs = z.abs.sub(y.abs, x.abs)
} }
} }
if len(z.abs) == 0 { if len(z.abs) == 0 {
...@@ -94,7 +94,7 @@ func (z *Int) Mul(x, y *Int) *Int { ...@@ -94,7 +94,7 @@ func (z *Int) Mul(x, y *Int) *Int {
// x * (-y) == -(x * y) // x * (-y) == -(x * y)
// (-x) * y == -(x * y) // (-x) * y == -(x * y)
// (-x) * (-y) == x * y // (-x) * (-y) == x * y
z.abs = mulNN(z.abs, x.abs, y.abs) z.abs = z.abs.mul(x.abs, y.abs)
z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
return z return z
} }
...@@ -126,14 +126,14 @@ func (z *Int) DivMod(x, y, r *Int) (*Int, *Int) { ...@@ -126,14 +126,14 @@ func (z *Int) DivMod(x, y, r *Int) (*Int, *Int) {
func div(q, r, x, y *Int) { func div(q, r, x, y *Int) {
q.neg = x.neg != y.neg q.neg = x.neg != y.neg
r.neg = x.neg r.neg = x.neg
q.abs, r.abs = divNN(q.abs, r.abs, x.abs, y.abs) q.abs, r.abs = q.abs.div(r.abs, x.abs, y.abs)
return return
} }
// Neg computes z = -x. // Neg computes z = -x.
func (z *Int) Neg(x *Int) *Int { func (z *Int) Neg(x *Int) *Int {
z.abs = setN(z.abs, x.abs) z.abs = z.abs.set(x.abs)
z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign
return z return z
} }
...@@ -152,7 +152,7 @@ func (x *Int) Cmp(y *Int) (r int) { ...@@ -152,7 +152,7 @@ func (x *Int) Cmp(y *Int) (r int) {
// (-x) cmp (-y) == -(x cmp y) // (-x) cmp (-y) == -(x cmp y)
switch { switch {
case x.neg == y.neg: case x.neg == y.neg:
r = cmpNN(x.abs, y.abs) r = x.abs.cmp(y.abs)
if x.neg { if x.neg {
r = -r r = -r
} }
...@@ -170,7 +170,7 @@ func (z *Int) String() string { ...@@ -170,7 +170,7 @@ func (z *Int) String() string {
if z.neg { if z.neg {
s = "-" s = "-"
} }
return s + stringN(z.abs, 10) return s + z.abs.string(10)
} }
...@@ -212,7 +212,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) { ...@@ -212,7 +212,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
z.neg = false z.neg = false
} }
z.abs, _, scanned = scanN(z.abs, s, base) z.abs, _, scanned = z.abs.scan(s, base)
if scanned != len(s) { if scanned != len(s) {
goto Error goto Error
} }
...@@ -230,7 +230,7 @@ Error: ...@@ -230,7 +230,7 @@ Error:
// sets z to that value. // sets z to that value.
func (z *Int) SetBytes(b []byte) *Int { func (z *Int) SetBytes(b []byte) *Int {
s := int(_S) s := int(_S)
z.abs = makeN(z.abs, (len(b)+s-1)/s, false) z.abs = z.abs.make((len(b)+s-1)/s, false)
z.neg = false z.neg = false
j := 0 j := 0
...@@ -258,7 +258,7 @@ func (z *Int) SetBytes(b []byte) *Int { ...@@ -258,7 +258,7 @@ func (z *Int) SetBytes(b []byte) *Int {
z.abs[j] = w z.abs[j] = w
} }
z.abs = normN(z.abs) z.abs = z.abs.norm()
return z return z
} }
...@@ -306,12 +306,12 @@ func (z *Int) Exp(x, y, m *Int) *Int { ...@@ -306,12 +306,12 @@ func (z *Int) Exp(x, y, m *Int) *Int {
return z return z
} }
var mWords []Word var mWords nat
if m != nil { if m != nil {
mWords = m.abs mWords = m.abs
} }
z.abs = expNNN(z.abs, x.abs, y.abs, mWords) z.abs = z.abs.expNN(x.abs, y.abs, mWords)
z.neg = x.neg && y.abs[0]&1 == 1 z.neg = x.neg && y.abs[0]&1 == 1
return z return z
} }
...@@ -379,20 +379,20 @@ func GcdInt(d, x, y, a, b *Int) { ...@@ -379,20 +379,20 @@ func GcdInt(d, x, y, a, b *Int) {
// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime. // ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
// If it returns true, z is prime with probability 1 - 1/4^n. // If it returns true, z is prime with probability 1 - 1/4^n.
// If it returns false, z is not prime. // If it returns false, z is not prime.
func ProbablyPrime(z *Int, n int) bool { return !z.neg && probablyPrime(z.abs, n) } func ProbablyPrime(z *Int, n int) bool { return !z.neg && z.abs.probablyPrime(n) }
// Lsh sets z = x << n and returns z. // Lsh sets z = x << n and returns z.
func (z *Int) Lsh(x *Int, n uint) *Int { func (z *Int) Lsh(x *Int, n uint) *Int {
addedWords := int(n) / _W addedWords := int(n) / _W
// Don't assign z.abs yet, in case z == x // Don't assign z.abs yet, in case z == x
znew := makeN(z.abs, len(x.abs)+addedWords+1, false) znew := z.abs.make(len(x.abs)+addedWords+1, false)
z.neg = x.neg z.neg = x.neg
shiftLeft(znew[addedWords:], x.abs, n%_W) znew[addedWords:].shiftLeft(x.abs, n%_W)
for i := range znew[0:addedWords] { for i := range znew[0:addedWords] {
znew[i] = 0 znew[i] = 0
} }
z.abs = normN(znew) z.abs = znew.norm()
return z return z
} }
...@@ -401,9 +401,9 @@ func (z *Int) Lsh(x *Int, n uint) *Int { ...@@ -401,9 +401,9 @@ func (z *Int) Lsh(x *Int, n uint) *Int {
func (z *Int) Rsh(x *Int, n uint) *Int { func (z *Int) Rsh(x *Int, n uint) *Int {
removedWords := int(n) / _W removedWords := int(n) / _W
// Don't assign z.abs yet, in case z == x // Don't assign z.abs yet, in case z == x
znew := makeN(z.abs, len(x.abs)-removedWords, false) znew := z.abs.make(len(x.abs)-removedWords, false)
z.neg = x.neg z.neg = x.neg
shiftRight(znew, x.abs[removedWords:], n%_W) znew.shiftRight(x.abs[removedWords:], n%_W)
z.abs = normN(znew) z.abs = znew.norm()
return z return z
} }
...@@ -327,8 +327,8 @@ func TestDivStepD6(t *testing.T) { ...@@ -327,8 +327,8 @@ func TestDivStepD6(t *testing.T) {
// See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
// a code path which only triggers 1 in 10^{-19} cases. // a code path which only triggers 1 in 10^{-19} cases.
u := &Int{false, []Word{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}} u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
v := &Int{false, []Word{5, 2 + 1<<(_W-1), 1 << (_W - 1)}} v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
r := new(Int) r := new(Int)
q, r := new(Int).DivMod(u, v, r) q, r := new(Int).DivMod(u, v, r)
......
...@@ -34,10 +34,9 @@ import "rand" ...@@ -34,10 +34,9 @@ import "rand"
// always normalized before returning the final result. The normalized // always normalized before returning the final result. The normalized
// representation of 0 is the empty or nil slice (length = 0). // representation of 0 is the empty or nil slice (length = 0).
// TODO(gri) - convert these routines into methods for type 'nat' type nat []Word
// - decide if type 'nat' should be exported
func normN(z []Word) []Word { func (z nat) norm() nat {
i := len(z) i := len(z)
for i > 0 && z[i-1] == 0 { for i > 0 && z[i-1] == 0 {
i-- i--
...@@ -47,7 +46,7 @@ func normN(z []Word) []Word { ...@@ -47,7 +46,7 @@ func normN(z []Word) []Word {
} }
func makeN(z []Word, m int, clear bool) []Word { func (z nat) make(m int, clear bool) nat {
if cap(z) > m { if cap(z) > m {
z = z[0:m] // reuse z - has at least one extra word for a carry, if any z = z[0:m] // reuse z - has at least one extra word for a carry, if any
if clear { if clear {
...@@ -62,18 +61,18 @@ func makeN(z []Word, m int, clear bool) []Word { ...@@ -62,18 +61,18 @@ func makeN(z []Word, m int, clear bool) []Word {
if m > c { if m > c {
c = m c = m
} }
return make([]Word, m, c+1) // +1: extra word for a carry, if any return make(nat, m, c+1) // +1: extra word for a carry, if any
} }
func newN(z []Word, x uint64) []Word { func (z nat) new(x uint64) nat {
if x == 0 { if x == 0 {
return makeN(z, 0, false) return z.make(0, false)
} }
// single-digit values // single-digit values
if x == uint64(Word(x)) { if x == uint64(Word(x)) {
z = makeN(z, 1, false) z = z.make(1, false)
z[0] = Word(x) z[0] = Word(x)
return z return z
} }
...@@ -85,7 +84,7 @@ func newN(z []Word, x uint64) []Word { ...@@ -85,7 +84,7 @@ func newN(z []Word, x uint64) []Word {
} }
// split x into n words // split x into n words
z = makeN(z, n, false) z = z.make(n, false)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
z[i] = Word(x & _M) z[i] = Word(x & _M)
x >>= _W x >>= _W
...@@ -95,8 +94,8 @@ func newN(z []Word, x uint64) []Word { ...@@ -95,8 +94,8 @@ func newN(z []Word, x uint64) []Word {
} }
func setN(z, x []Word) []Word { func (z nat) set(x nat) nat {
z = makeN(z, len(x), false) z = z.make(len(x), false)
for i, d := range x { for i, d := range x {
z[i] = d z[i] = d
} }
...@@ -104,23 +103,23 @@ func setN(z, x []Word) []Word { ...@@ -104,23 +103,23 @@ func setN(z, x []Word) []Word {
} }
func addNN(z, x, y []Word) []Word { func (z nat) add(x, y nat) nat {
m := len(x) m := len(x)
n := len(y) n := len(y)
switch { switch {
case m < n: case m < n:
return addNN(z, y, x) return z.add(y, x)
case m == 0: case m == 0:
// n == 0 because m >= n; result is 0 // n == 0 because m >= n; result is 0
return makeN(z, 0, false) return z.make(0, false)
case n == 0: case n == 0:
// result is x // result is x
return setN(z, x) return z.set(x)
} }
// m > 0 // m > 0
z = makeN(z, m, false) z = z.make(m, false)
c := addVV(&z[0], &x[0], &y[0], n) c := addVV(&z[0], &x[0], &y[0], n)
if m > n { if m > n {
c = addVW(&z[n], &x[n], c, m-n) c = addVW(&z[n], &x[n], c, m-n)
...@@ -134,7 +133,7 @@ func addNN(z, x, y []Word) []Word { ...@@ -134,7 +133,7 @@ func addNN(z, x, y []Word) []Word {
} }
func subNN(z, x, y []Word) []Word { func (z nat) sub(x, y nat) nat {
m := len(x) m := len(x)
n := len(y) n := len(y)
...@@ -143,14 +142,14 @@ func subNN(z, x, y []Word) []Word { ...@@ -143,14 +142,14 @@ func subNN(z, x, y []Word) []Word {
panic("underflow") panic("underflow")
case m == 0: case m == 0:
// n == 0 because m >= n; result is 0 // n == 0 because m >= n; result is 0
return makeN(z, 0, false) return z.make(0, false)
case n == 0: case n == 0:
// result is x // result is x
return setN(z, x) return z.set(x)
} }
// m > 0 // m > 0
z = makeN(z, m, false) z = z.make(m, false)
c := subVV(&z[0], &x[0], &y[0], n) c := subVV(&z[0], &x[0], &y[0], n)
if m > n { if m > n {
c = subVW(&z[n], &x[n], c, m-n) c = subVW(&z[n], &x[n], c, m-n)
...@@ -158,13 +157,13 @@ func subNN(z, x, y []Word) []Word { ...@@ -158,13 +157,13 @@ func subNN(z, x, y []Word) []Word {
if c != 0 { if c != 0 {
panic("underflow") panic("underflow")
} }
z = normN(z) z = z.norm()
return z return z
} }
func cmpNN(x, y []Word) (r int) { func (x nat) cmp(y nat) (r int) {
m := len(x) m := len(x)
n := len(y) n := len(y)
if m != n || m == 0 { if m != n || m == 0 {
...@@ -192,14 +191,14 @@ func cmpNN(x, y []Word) (r int) { ...@@ -192,14 +191,14 @@ func cmpNN(x, y []Word) (r int) {
} }
func mulAddNWW(z, x []Word, y, r Word) []Word { func (z nat) mulAddWW(x nat, y, r Word) nat {
m := len(x) m := len(x)
if m == 0 || y == 0 { if m == 0 || y == 0 {
return newN(z, uint64(r)) // result is r return z.new(uint64(r)) // result is r
} }
// m > 0 // m > 0
z = makeN(z, m, false) z = z.make(m, false)
c := mulAddVWW(&z[0], &x[0], y, r, m) c := mulAddVWW(&z[0], &x[0], y, r, m)
if c > 0 { if c > 0 {
z = z[0 : m+1] z = z[0 : m+1]
...@@ -210,81 +209,81 @@ func mulAddNWW(z, x []Word, y, r Word) []Word { ...@@ -210,81 +209,81 @@ func mulAddNWW(z, x []Word, y, r Word) []Word {
} }
func mulNN(z, x, y []Word) []Word { func (z nat) mul(x, y nat) nat {
m := len(x) m := len(x)
n := len(y) n := len(y)
switch { switch {
case m < n: case m < n:
return mulNN(z, y, x) return z.mul(y, x)
case m == 0 || n == 0: case m == 0 || n == 0:
return makeN(z, 0, false) return z.make(0, false)
case n == 1: case n == 1:
return mulAddNWW(z, x, y[0], 0) return z.mulAddWW(x, y[0], 0)
} }
// m >= n && m > 1 && n > 1 // m >= n && m > 1 && n > 1
if z == nil || &z[0] == &x[0] || &z[0] == &y[0] { if z == nil || &z[0] == &x[0] || &z[0] == &y[0] {
z = makeN(nil, m+n, true) // z is an alias for x or y - cannot reuse z = nat(nil).make(m+n, true) // z is an alias for x or y - cannot reuse
} else { } else {
z = makeN(z, m+n, true) z = z.make(m+n, true)
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
if f := y[i]; f != 0 { if f := y[i]; f != 0 {
z[m+i] = addMulVVW(&z[i], &x[0], f, m) z[m+i] = addMulVVW(&z[i], &x[0], f, m)
} }
} }
z = normN(z) z = z.norm()
return z return z
} }
// q = (x-r)/y, with 0 <= r < y // q = (x-r)/y, with 0 <= r < y
func divNW(z, x []Word, y Word) (q []Word, r Word) { func (z nat) divW(x nat, y Word) (q nat, r Word) {
m := len(x) m := len(x)
switch { switch {
case y == 0: case y == 0:
panic("division by zero") panic("division by zero")
case y == 1: case y == 1:
q = setN(z, x) // result is x q = z.set(x) // result is x
return return
case m == 0: case m == 0:
q = setN(z, nil) // result is 0 q = z.set(nil) // result is 0
return return
} }
// m > 0 // m > 0
z = makeN(z, m, false) z = z.make(m, false)
r = divWVW(&z[0], 0, &x[0], y, m) r = divWVW(&z[0], 0, &x[0], y, m)
q = normN(z) q = z.norm()
return return
} }
func divNN(z, z2, u, v []Word) (q, r []Word) { func (z nat) div(z2, u, v nat) (q, r nat) {
if len(v) == 0 { if len(v) == 0 {
panic("Divide by zero undefined") panic("division by zero")
} }
if cmpNN(u, v) < 0 { if u.cmp(v) < 0 {
q = makeN(z, 0, false) q = z.make(0, false)
r = setN(z2, u) r = z2.set(u)
return return
} }
if len(v) == 1 { if len(v) == 1 {
var rprime Word var rprime Word
q, rprime = divNW(z, u, v[0]) q, rprime = z.divW(u, v[0])
if rprime > 0 { if rprime > 0 {
r = makeN(z2, 1, false) r = z2.make(1, false)
r[0] = rprime r[0] = rprime
} else { } else {
r = makeN(z2, 0, false) r = z2.make(0, false)
} }
return return
} }
q, r = divLargeNN(z, z2, u, v) q, r = z.divLarge(z2, u, v)
return return
} }
...@@ -294,23 +293,23 @@ func divNN(z, z2, u, v []Word) (q, r []Word) { ...@@ -294,23 +293,23 @@ func divNN(z, z2, u, v []Word) (q, r []Word) {
// Preconditions: // Preconditions:
// len(v) >= 2 // len(v) >= 2
// len(uIn) >= len(v) // len(uIn) >= len(v)
func divLargeNN(z, z2, uIn, v []Word) (q, r []Word) { func (z nat) divLarge(z2, uIn, v nat) (q, r nat) {
n := len(v) n := len(v)
m := len(uIn) - len(v) m := len(uIn) - len(v)
var u []Word var u nat
if z2 == nil || &z2[0] == &uIn[0] { if z2 == nil || &z2[0] == &uIn[0] {
u = makeN(nil, len(uIn)+1, true) // uIn is an alias for z2 u = u.make(len(uIn)+1, true) // uIn is an alias for z2
} else { } else {
u = makeN(z2, len(uIn)+1, true) u = z2.make(len(uIn)+1, true)
} }
qhatv := make([]Word, len(v)+1) qhatv := make(nat, len(v)+1)
q = makeN(z, m+1, false) q = z.make(m+1, false)
// D1. // D1.
shift := uint(leadingZeroBits(v[n-1])) shift := uint(leadingZeroBits(v[n-1]))
shiftLeft(v, v, shift) v.shiftLeft(v, shift)
shiftLeft(u, uIn, shift) u.shiftLeft(uIn, shift)
u[len(uIn)] = uIn[len(uIn)-1] >> (_W - uint(shift)) u[len(uIn)] = uIn[len(uIn)-1] >> (_W - uint(shift))
// D2. // D2.
...@@ -351,10 +350,10 @@ func divLargeNN(z, z2, uIn, v []Word) (q, r []Word) { ...@@ -351,10 +350,10 @@ func divLargeNN(z, z2, uIn, v []Word) (q, r []Word) {
q[j] = qhat q[j] = qhat
} }
q = normN(q) q = q.norm()
shiftRight(u, u, shift) u.shiftRight(u, shift)
shiftRight(v, v, shift) v.shiftRight(v, shift)
r = normN(u) r = u.norm()
return q, r return q, r
} }
...@@ -372,10 +371,10 @@ func log2(x Word) int { ...@@ -372,10 +371,10 @@ func log2(x Word) int {
} }
// log2N computes the integer binary logarithm of x. // log2 computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1). // The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1. // If x == 0, the result is -1.
func log2N(x []Word) int { func (x nat) log2() int {
m := len(x) m := len(x)
if m > 0 { if m > 0 {
return (m-1)*_W + log2(x[m-1]) return (m-1)*_W + log2(x[m-1])
...@@ -410,7 +409,7 @@ func hexValue(ch byte) int { ...@@ -410,7 +409,7 @@ func hexValue(ch byte) int {
// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the // conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
// ``0'' prefix selects base 8. Otherwise the selected base is 10. // ``0'' prefix selects base 8. Otherwise the selected base is 10.
// //
func scanN(z []Word, s string, base int) ([]Word, int, int) { func (z nat) scan(s string, base int) (nat, int, int) {
// determine base if necessary // determine base if necessary
i, n := 0, len(s) i, n := 0, len(s)
if base == 0 { if base == 0 {
...@@ -436,7 +435,7 @@ func scanN(z []Word, s string, base int) ([]Word, int, int) { ...@@ -436,7 +435,7 @@ func scanN(z []Word, s string, base int) ([]Word, int, int) {
for ; i < n; i++ { for ; i < n; i++ {
d := hexValue(s[i]) d := hexValue(s[i])
if 0 <= d && d < base { if 0 <= d && d < base {
z = mulAddNWW(z, z, Word(base), Word(d)) z = z.mulAddWW(z, Word(base), Word(d))
} else { } else {
break break
} }
...@@ -449,7 +448,7 @@ func scanN(z []Word, s string, base int) ([]Word, int, int) { ...@@ -449,7 +448,7 @@ func scanN(z []Word, s string, base int) ([]Word, int, int) {
// string converts x to a string for a given base, with 2 <= base <= 16. // string converts x to a string for a given base, with 2 <= base <= 16.
// TODO(gri) in the style of the other routines, perhaps this should take // TODO(gri) in the style of the other routines, perhaps this should take
// a []byte buffer and return it // a []byte buffer and return it
func stringN(x []Word, base int) string { func (x nat) string(base int) string {
if base < 2 || 16 < base { if base < 2 || 16 < base {
panic("illegal base") panic("illegal base")
} }
...@@ -459,17 +458,17 @@ func stringN(x []Word, base int) string { ...@@ -459,17 +458,17 @@ func stringN(x []Word, base int) string {
} }
// allocate buffer for conversion // allocate buffer for conversion
i := (log2N(x)+1)/log2(Word(base)) + 1 // +1: round up i := (x.log2()+1)/log2(Word(base)) + 1 // +1: round up
s := make([]byte, i) s := make([]byte, i)
// don't destroy x // don't destroy x
q := setN(nil, x) q := nat(nil).set(x)
// convert // convert
for len(q) > 0 { for len(q) > 0 {
i-- i--
var r Word var r Word
q, r = divNW(q, q, Word(base)) q, r = q.divW(q, Word(base))
s[i] = "0123456789abcdef"[r] s[i] = "0123456789abcdef"[r]
} }
...@@ -536,40 +535,42 @@ func trailingZeroBits(x Word) int { ...@@ -536,40 +535,42 @@ func trailingZeroBits(x Word) int {
} }
// To avoid losing the top n bits, dst should be sized so that // To avoid losing the top n bits, z should be sized so that
// len(dst) == len(src) + 1. // len(z) == len(x) + 1.
func shiftLeft(dst, src []Word, n uint) { func (z nat) shiftLeft(x nat, n uint) nat {
if len(src) == 0 { if len(x) == 0 {
return return x
} }
ñ := _W - n ñ := _W - n
x := src[len(src)-1] m := x[len(x)-1]
if len(dst) > len(src) { if len(z) > len(x) {
dst[len(src)] = x >> ñ z[len(x)] = m >> ñ
} }
for i := len(src) - 1; i >= 1; i-- { for i := len(x) - 1; i >= 1; i-- {
y := src[i-1] y := x[i-1]
dst[i] = x<<n | y>>ñ z[i] = m<<n | y>>ñ
x = y m = y
} }
dst[0] = x << n z[0] = m << n
return z
} }
func shiftRight(dst, src []Word, n uint) { func (z nat) shiftRight(x nat, n uint) nat {
if len(src) == 0 { if len(x) == 0 {
return return x
} }
ñ := _W - n ñ := _W - n
x := src[0] m := x[0]
for i := 0; i < len(src)-1; i++ { for i := 0; i < len(x)-1; i++ {
y := src[i+1] y := x[i+1]
dst[i] = x>>n | y<<ñ z[i] = m>>n | y<<ñ
x = y m = y
} }
dst[len(src)-1] = x >> n z[len(x)-1] = m >> n
return z
} }
...@@ -577,16 +578,17 @@ func shiftRight(dst, src []Word, n uint) { ...@@ -577,16 +578,17 @@ func shiftRight(dst, src []Word, n uint) {
func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 } func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
// modNW returns x % d. // modW returns x % d.
func modNW(x []Word, d Word) (r Word) { func (x nat) modW(d Word) (r Word) {
// TODO(agl): we don't actually need to store the q value. // TODO(agl): we don't actually need to store the q value.
q := makeN(nil, len(x), false) var q nat
q = q.make(len(x), false)
return divWVW(&q[0], 0, &x[0], d, len(x)) return divWVW(&q[0], 0, &x[0], d, len(x))
} }
// powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd. // powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd.
func powersOfTwoDecompose(n []Word) (q []Word, k Word) { func (n nat) powersOfTwoDecompose() (q nat, k Word) {
if len(n) == 0 { if len(n) == 0 {
return n, 0 return n, 0
} }
...@@ -599,24 +601,24 @@ func powersOfTwoDecompose(n []Word) (q []Word, k Word) { ...@@ -599,24 +601,24 @@ func powersOfTwoDecompose(n []Word) (q []Word, k Word) {
// zeroWords < len(n). // zeroWords < len(n).
x := trailingZeroBits(n[zeroWords]) x := trailingZeroBits(n[zeroWords])
q = makeN(nil, len(n)-zeroWords, false) q = q.make(len(n)-zeroWords, false)
shiftRight(q, n[zeroWords:], uint(x)) q.shiftRight(n[zeroWords:], uint(x))
q = normN(q) q = q.norm()
k = Word(_W*zeroWords + x) k = Word(_W*zeroWords + x)
return return
} }
// randomN creates a random integer in [0..limit), using the space in z if // random creates a random integer in [0..limit), using the space in z if
// possible. n is the bit length of limit. // possible. n is the bit length of limit.
func randomN(z []Word, rand *rand.Rand, limit []Word, n int) []Word { func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
bitLengthOfMSW := uint(n % _W) bitLengthOfMSW := uint(n % _W)
if bitLengthOfMSW == 0 { if bitLengthOfMSW == 0 {
bitLengthOfMSW = _W bitLengthOfMSW = _W
} }
mask := Word((1 << bitLengthOfMSW) - 1) mask := Word((1 << bitLengthOfMSW) - 1)
z = makeN(z, len(limit), false) z = z.make(len(limit), false)
for { for {
for i := range z { for i := range z {
...@@ -630,35 +632,35 @@ func randomN(z []Word, rand *rand.Rand, limit []Word, n int) []Word { ...@@ -630,35 +632,35 @@ func randomN(z []Word, rand *rand.Rand, limit []Word, n int) []Word {
z[len(limit)-1] &= mask z[len(limit)-1] &= mask
if cmpNN(z, limit) < 0 { if z.cmp(limit) < 0 {
break break
} }
} }
return normN(z) return z.norm()
} }
// If m != nil, expNNN calculates x**y mod m. Otherwise it calculates x**y. It // If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It
// reuses the storage of z if possible. // reuses the storage of z if possible.
func expNNN(z, x, y, m []Word) []Word { func (z nat) expNN(x, y, m nat) nat {
if len(y) == 0 { if len(y) == 0 {
z = makeN(z, 1, false) z = z.make(1, false)
z[0] = 1 z[0] = 1
return z return z
} }
if m != nil { if m != nil {
// We likely end up being as long as the modulus. // We likely end up being as long as the modulus.
z = makeN(z, len(m), false) z = z.make(len(m), false)
} }
z = setN(z, x) z = z.set(x)
v := y[len(y)-1] v := y[len(y)-1]
// It's invalid for the most significant word to be zero, therefore we // It's invalid for the most significant word to be zero, therefore we
// will find a one bit. // will find a one bit.
shift := leadingZeros(v) + 1 shift := leadingZeros(v) + 1
v <<= shift v <<= shift
var q []Word var q nat
const mask = 1 << (_W - 1) const mask = 1 << (_W - 1)
...@@ -668,14 +670,14 @@ func expNNN(z, x, y, m []Word) []Word { ...@@ -668,14 +670,14 @@ func expNNN(z, x, y, m []Word) []Word {
w := _W - int(shift) w := _W - int(shift)
for j := 0; j < w; j++ { for j := 0; j < w; j++ {
z = mulNN(z, z, z) z = z.mul(z, z)
if v&mask != 0 { if v&mask != 0 {
z = mulNN(z, z, x) z = z.mul(z, x)
} }
if m != nil { if m != nil {
q, z = divNN(q, z, z, m) q, z = q.div(z, z, m)
} }
v <<= 1 v <<= 1
...@@ -685,14 +687,14 @@ func expNNN(z, x, y, m []Word) []Word { ...@@ -685,14 +687,14 @@ func expNNN(z, x, y, m []Word) []Word {
v = y[i] v = y[i]
for j := 0; j < _W; j++ { for j := 0; j < _W; j++ {
z = mulNN(z, z, z) z = z.mul(z, z)
if v&mask != 0 { if v&mask != 0 {
z = mulNN(z, z, x) z = z.mul(z, x)
} }
if m != nil { if m != nil {
q, z = divNN(q, z, z, m) q, z = q.div(z, z, m)
} }
v <<= 1 v <<= 1
...@@ -703,8 +705,8 @@ func expNNN(z, x, y, m []Word) []Word { ...@@ -703,8 +705,8 @@ func expNNN(z, x, y, m []Word) []Word {
} }
// lenN returns the bit length of z. // len returns the bit length of z.
func lenN(z []Word) int { func (z nat) len() int {
if len(z) == 0 { if len(z) == 0 {
return 0 return 0
} }
...@@ -718,13 +720,13 @@ const ( ...@@ -718,13 +720,13 @@ const (
primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53} primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
) )
var bigOne = []Word{1} var bigOne = nat{1}
var bigTwo = []Word{2} var bigTwo = nat{2}
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime. // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
// If it returns true, n is prime with probability 1 - 1/4^reps. // If it returns true, n is prime with probability 1 - 1/4^reps.
// If it returns false, n is not prime. // If it returns false, n is not prime.
func probablyPrime(n []Word, reps int) bool { func (n nat) probablyPrime(reps int) bool {
if len(n) == 0 { if len(n) == 0 {
return false return false
} }
...@@ -751,9 +753,9 @@ func probablyPrime(n []Word, reps int) bool { ...@@ -751,9 +753,9 @@ func probablyPrime(n []Word, reps int) bool {
var r Word var r Word
switch _W { switch _W {
case 32: case 32:
r = modNW(n, primesProduct32) r = n.modW(primesProduct32)
case 64: case 64:
r = modNW(n, primesProduct64&_M) r = n.modW(primesProduct64 & _M)
default: default:
panic("Unknown word size") panic("Unknown word size")
} }
...@@ -768,31 +770,31 @@ func probablyPrime(n []Word, reps int) bool { ...@@ -768,31 +770,31 @@ func probablyPrime(n []Word, reps int) bool {
return false return false
} }
nm1 := subNN(nil, n, bigOne) nm1 := nat(nil).sub(n, bigOne)
// 1<<k * q = nm1; // 1<<k * q = nm1;
q, k := powersOfTwoDecompose(nm1) q, k := nm1.powersOfTwoDecompose()
nm3 := subNN(nil, nm1, bigTwo) nm3 := nat(nil).sub(nm1, bigTwo)
rand := rand.New(rand.NewSource(int64(n[0]))) rand := rand.New(rand.NewSource(int64(n[0])))
var x, y, quotient []Word var x, y, quotient nat
nm3Len := lenN(nm3) nm3Len := nm3.len()
NextRandom: NextRandom:
for i := 0; i < reps; i++ { for i := 0; i < reps; i++ {
x = randomN(x, rand, nm3, nm3Len) x = x.random(rand, nm3, nm3Len)
x = addNN(x, x, bigTwo) x = x.add(x, bigTwo)
y = expNNN(y, x, q, n) y = y.expNN(x, q, n)
if cmpNN(y, bigOne) == 0 || cmpNN(y, nm1) == 0 { if y.cmp(bigOne) == 0 || y.cmp(nm1) == 0 {
continue continue
} }
for j := Word(1); j < k; j++ { for j := Word(1); j < k; j++ {
y = mulNN(y, y, y) y = y.mul(y, y)
quotient, y = divNN(quotient, y, y, n) quotient, y = quotient.div(y, y, n)
if cmpNN(y, nm1) == 0 { if y.cmp(nm1) == 0 {
continue NextRandom continue NextRandom
} }
if cmpNN(y, bigOne) == 0 { if y.cmp(bigOne) == 0 {
return false return false
} }
} }
......
...@@ -7,32 +7,32 @@ package big ...@@ -7,32 +7,32 @@ package big
import "testing" import "testing"
type cmpTest struct { type cmpTest struct {
x, y []Word x, y nat
r int r int
} }
var cmpTests = []cmpTest{ var cmpTests = []cmpTest{
cmpTest{nil, nil, 0}, cmpTest{nil, nil, 0},
cmpTest{nil, []Word{}, 0}, cmpTest{nil, nat{}, 0},
cmpTest{[]Word{}, nil, 0}, cmpTest{nat{}, nil, 0},
cmpTest{[]Word{}, []Word{}, 0}, cmpTest{nat{}, nat{}, 0},
cmpTest{[]Word{0}, []Word{0}, 0}, cmpTest{nat{0}, nat{0}, 0},
cmpTest{[]Word{0}, []Word{1}, -1}, cmpTest{nat{0}, nat{1}, -1},
cmpTest{[]Word{1}, []Word{0}, 1}, cmpTest{nat{1}, nat{0}, 1},
cmpTest{[]Word{1}, []Word{1}, 0}, cmpTest{nat{1}, nat{1}, 0},
cmpTest{[]Word{0, _M}, []Word{1}, 1}, cmpTest{nat{0, _M}, nat{1}, 1},
cmpTest{[]Word{1}, []Word{0, _M}, -1}, cmpTest{nat{1}, nat{0, _M}, -1},
cmpTest{[]Word{1, _M}, []Word{0, _M}, 1}, cmpTest{nat{1, _M}, nat{0, _M}, 1},
cmpTest{[]Word{0, _M}, []Word{1, _M}, -1}, cmpTest{nat{0, _M}, nat{1, _M}, -1},
cmpTest{[]Word{16, 571956, 8794, 68}, []Word{837, 9146, 1, 754489}, -1}, cmpTest{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
cmpTest{[]Word{34986, 41, 105, 1957}, []Word{56, 7458, 104, 1957}, 1}, cmpTest{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
} }
func TestCmpNN(t *testing.T) { func TestCmp(t *testing.T) {
for i, a := range cmpTests { for i, a := range cmpTests {
r := cmpNN(a.x, a.y) r := a.x.cmp(a.y)
if r != a.r { if r != a.r {
t.Errorf("#%d got r = %v; want %v", i, r, a.r) t.Errorf("#%d got r = %v; want %v", i, r, a.r)
} }
...@@ -40,38 +40,38 @@ func TestCmpNN(t *testing.T) { ...@@ -40,38 +40,38 @@ func TestCmpNN(t *testing.T) {
} }
type funNN func(z, x, y []Word) []Word type funNN func(z, x, y nat) nat
type argNN struct { type argNN struct {
z, x, y []Word z, x, y nat
} }
var sumNN = []argNN{ var sumNN = []argNN{
argNN{}, argNN{},
argNN{[]Word{1}, nil, []Word{1}}, argNN{nat{1}, nil, nat{1}},
argNN{[]Word{1111111110}, []Word{123456789}, []Word{987654321}}, argNN{nat{1111111110}, nat{123456789}, nat{987654321}},
argNN{[]Word{0, 0, 0, 1}, nil, []Word{0, 0, 0, 1}}, argNN{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
argNN{[]Word{0, 0, 0, 1111111110}, []Word{0, 0, 0, 123456789}, []Word{0, 0, 0, 987654321}}, argNN{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
argNN{[]Word{0, 0, 0, 1}, []Word{0, 0, _M}, []Word{0, 0, 1}}, argNN{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
} }
var prodNN = []argNN{ var prodNN = []argNN{
argNN{}, argNN{},
argNN{nil, nil, nil}, argNN{nil, nil, nil},
argNN{nil, []Word{991}, nil}, argNN{nil, nat{991}, nil},
argNN{[]Word{991}, []Word{991}, []Word{1}}, argNN{nat{991}, nat{991}, nat{1}},
argNN{[]Word{991 * 991}, []Word{991}, []Word{991}}, argNN{nat{991 * 991}, nat{991}, nat{991}},
argNN{[]Word{0, 0, 991 * 991}, []Word{0, 991}, []Word{0, 991}}, argNN{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
argNN{[]Word{1 * 991, 2 * 991, 3 * 991, 4 * 991}, []Word{1, 2, 3, 4}, []Word{991}}, argNN{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
argNN{[]Word{4, 11, 20, 30, 20, 11, 4}, []Word{1, 2, 3, 4}, []Word{4, 3, 2, 1}}, argNN{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
} }
func TestSetN(t *testing.T) { func TestSet(t *testing.T) {
for _, a := range sumNN { for _, a := range sumNN {
z := setN(nil, a.z) z := nat(nil).set(a.z)
if cmpNN(z, a.z) != 0 { if z.cmp(a.z) != 0 {
t.Errorf("got z = %v; want %v", z, a.z) t.Errorf("got z = %v; want %v", z, a.z)
} }
} }
...@@ -80,7 +80,7 @@ func TestSetN(t *testing.T) { ...@@ -80,7 +80,7 @@ func TestSetN(t *testing.T) {
func testFunNN(t *testing.T, msg string, f funNN, a argNN) { func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
z := f(nil, a.x, a.y) z := f(nil, a.x, a.y)
if cmpNN(z, a.z) != 0 { if z.cmp(a.z) != 0 {
t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z) t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
} }
} }
...@@ -89,30 +89,30 @@ func testFunNN(t *testing.T, msg string, f funNN, a argNN) { ...@@ -89,30 +89,30 @@ func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
func TestFunNN(t *testing.T) { func TestFunNN(t *testing.T) {
for _, a := range sumNN { for _, a := range sumNN {
arg := a arg := a
testFunNN(t, "addNN", addNN, arg) testFunNN(t, "add", nat.add, arg)
arg = argNN{a.z, a.y, a.x} arg = argNN{a.z, a.y, a.x}
testFunNN(t, "addNN symmetric", addNN, arg) testFunNN(t, "add symmetric", nat.add, arg)
arg = argNN{a.x, a.z, a.y} arg = argNN{a.x, a.z, a.y}
testFunNN(t, "subNN", subNN, arg) testFunNN(t, "sub", nat.sub, arg)
arg = argNN{a.y, a.z, a.x} arg = argNN{a.y, a.z, a.x}
testFunNN(t, "subNN symmetric", subNN, arg) testFunNN(t, "sub symmetric", nat.sub, arg)
} }
for _, a := range prodNN { for _, a := range prodNN {
arg := a arg := a
testFunNN(t, "mulNN", mulNN, arg) testFunNN(t, "mul", nat.mul, arg)
arg = argNN{a.z, a.y, a.x} arg = argNN{a.z, a.y, a.x}
testFunNN(t, "mulNN symmetric", mulNN, arg) testFunNN(t, "mul symmetric", nat.mul, arg)
} }
} }
type strN struct { type strN struct {
x []Word x nat
b int b int
s string s string
} }
...@@ -120,21 +120,21 @@ type strN struct { ...@@ -120,21 +120,21 @@ type strN struct {
var tabN = []strN{ var tabN = []strN{
strN{nil, 10, "0"}, strN{nil, 10, "0"},
strN{[]Word{1}, 10, "1"}, strN{nat{1}, 10, "1"},
strN{[]Word{10}, 10, "10"}, strN{nat{10}, 10, "10"},
strN{[]Word{1234567890}, 10, "1234567890"}, strN{nat{1234567890}, 10, "1234567890"},
} }
func TestStringN(t *testing.T) { func TestString(t *testing.T) {
for _, a := range tabN { for _, a := range tabN {
s := stringN(a.x, a.b) s := a.x.string(a.b)
if s != a.s { if s != a.s {
t.Errorf("stringN%+v\n\tgot s = %s; want %s", a, s, a.s) t.Errorf("stringN%+v\n\tgot s = %s; want %s", a, s, a.s)
} }
x, b, n := scanN(nil, a.s, a.b) x, b, n := nat(nil).scan(a.s, a.b)
if cmpNN(x, a.x) != 0 { if x.cmp(a.x) != 0 {
t.Errorf("scanN%+v\n\tgot z = %v; want %v", a, x, a.x) t.Errorf("scanN%+v\n\tgot z = %v; want %v", a, x, a.x)
} }
if b != a.b { if b != a.b {
...@@ -159,27 +159,27 @@ func TestLeadingZeroBits(t *testing.T) { ...@@ -159,27 +159,27 @@ func TestLeadingZeroBits(t *testing.T) {
type shiftTest struct { type shiftTest struct {
in []Word in nat
shift uint shift uint
out []Word out nat
} }
var leftShiftTests = []shiftTest{ var leftShiftTests = []shiftTest{
shiftTest{nil, 0, nil}, shiftTest{nil, 0, nil},
shiftTest{nil, 1, nil}, shiftTest{nil, 1, nil},
shiftTest{[]Word{0}, 0, []Word{0}}, shiftTest{nat{0}, 0, nat{0}},
shiftTest{[]Word{1}, 0, []Word{1}}, shiftTest{nat{1}, 0, nat{1}},
shiftTest{[]Word{1}, 1, []Word{2}}, shiftTest{nat{1}, 1, nat{2}},
shiftTest{[]Word{1 << (_W - 1)}, 1, []Word{0}}, shiftTest{nat{1 << (_W - 1)}, 1, nat{0}},
shiftTest{[]Word{1 << (_W - 1), 0}, 1, []Word{0, 1}}, shiftTest{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
} }
func TestShiftLeft(t *testing.T) { func TestShiftLeft(t *testing.T) {
for i, test := range leftShiftTests { for i, test := range leftShiftTests {
dst := make([]Word, len(test.out)) dst := make(nat, len(test.out))
shiftLeft(dst, test.in, test.shift) dst.shiftLeft(test.in, test.shift)
for j, v := range dst { for j, v := range dst {
if test.out[j] != v { if test.out[j] != v {
t.Errorf("#%d: got: %v want: %v", i, dst, test.out) t.Errorf("#%d: got: %v want: %v", i, dst, test.out)
...@@ -193,19 +193,19 @@ func TestShiftLeft(t *testing.T) { ...@@ -193,19 +193,19 @@ func TestShiftLeft(t *testing.T) {
var rightShiftTests = []shiftTest{ var rightShiftTests = []shiftTest{
shiftTest{nil, 0, nil}, shiftTest{nil, 0, nil},
shiftTest{nil, 1, nil}, shiftTest{nil, 1, nil},
shiftTest{[]Word{0}, 0, []Word{0}}, shiftTest{nat{0}, 0, nat{0}},
shiftTest{[]Word{1}, 0, []Word{1}}, shiftTest{nat{1}, 0, nat{1}},
shiftTest{[]Word{1}, 1, []Word{0}}, shiftTest{nat{1}, 1, nat{0}},
shiftTest{[]Word{2}, 1, []Word{1}}, shiftTest{nat{2}, 1, nat{1}},
shiftTest{[]Word{0, 1}, 1, []Word{1 << (_W - 1), 0}}, shiftTest{nat{0, 1}, 1, nat{1 << (_W - 1), 0}},
shiftTest{[]Word{2, 1, 1}, 1, []Word{1<<(_W-1) + 1, 1 << (_W - 1), 0}}, shiftTest{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1), 0}},
} }
func TestShiftRight(t *testing.T) { func TestShiftRight(t *testing.T) {
for i, test := range rightShiftTests { for i, test := range rightShiftTests {
dst := make([]Word, len(test.out)) dst := make(nat, len(test.out))
shiftRight(dst, test.in, test.shift) dst.shiftRight(test.in, test.shift)
for j, v := range dst { for j, v := range dst {
if test.out[j] != v { if test.out[j] != v {
t.Errorf("#%d: got: %v want: %v", i, dst, test.out) t.Errorf("#%d: got: %v want: %v", i, dst, test.out)
...@@ -216,30 +216,30 @@ func TestShiftRight(t *testing.T) { ...@@ -216,30 +216,30 @@ func TestShiftRight(t *testing.T) {
} }
type modNWTest struct { type modWTest struct {
in string in string
dividend string dividend string
out string out string
} }
var modNWTests32 = []modNWTest{ var modWTests32 = []modWTest{
modNWTest{"23492635982634928349238759823742", "252341", "220170"}, modWTest{"23492635982634928349238759823742", "252341", "220170"},
} }
var modNWTests64 = []modNWTest{ var modWTests64 = []modWTest{
modNWTest{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"}, modWTest{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
} }
func runModNWTests(t *testing.T, tests []modNWTest) { func runModWTests(t *testing.T, tests []modWTest) {
for i, test := range tests { for i, test := range tests {
in, _ := new(Int).SetString(test.in, 10) in, _ := new(Int).SetString(test.in, 10)
d, _ := new(Int).SetString(test.dividend, 10) d, _ := new(Int).SetString(test.dividend, 10)
out, _ := new(Int).SetString(test.out, 10) out, _ := new(Int).SetString(test.out, 10)
r := modNW(in.abs, d.abs[0]) r := in.abs.modW(d.abs[0])
if r != out.abs[0] { if r != out.abs[0] {
t.Errorf("#%d failed: got %s want %s\n", i, r, out) t.Errorf("#%d failed: got %s want %s\n", i, r, out)
} }
...@@ -247,12 +247,12 @@ func runModNWTests(t *testing.T, tests []modNWTest) { ...@@ -247,12 +247,12 @@ func runModNWTests(t *testing.T, tests []modNWTest) {
} }
func TestModNW(t *testing.T) { func TestModW(t *testing.T) {
if _W >= 32 { if _W >= 32 {
runModNWTests(t, modNWTests32) runModWTests(t, modWTests32)
} }
if _W >= 64 { if _W >= 64 {
runModNWTests(t, modNWTests32) runModWTests(t, modWTests64)
} }
} }
...@@ -269,19 +269,19 @@ func TestTrailingZeroBits(t *testing.T) { ...@@ -269,19 +269,19 @@ func TestTrailingZeroBits(t *testing.T) {
} }
type expNNNTest struct { type expNNTest struct {
x, y, m string x, y, m string
out string out string
} }
var expNNNTests = []expNNNTest{ var expNNTests = []expNNTest{
expNNNTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, expNNTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
expNNNTest{"0x8000000000000000", "2", "6719", "4944"}, expNNTest{"0x8000000000000000", "2", "6719", "4944"},
expNNNTest{"0x8000000000000000", "3", "6719", "5447"}, expNNTest{"0x8000000000000000", "3", "6719", "5447"},
expNNNTest{"0x8000000000000000", "1000", "6719", "1603"}, expNNTest{"0x8000000000000000", "1000", "6719", "1603"},
expNNNTest{"0x8000000000000000", "1000000", "6719", "3199"}, expNNTest{"0x8000000000000000", "1000000", "6719", "3199"},
expNNNTest{ expNNTest{
"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347", "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
"298472983472983471903246121093472394872319615612417471234712061", "298472983472983471903246121093472394872319615612417471234712061",
"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464", "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
...@@ -290,20 +290,20 @@ var expNNNTests = []expNNNTest{ ...@@ -290,20 +290,20 @@ var expNNNTests = []expNNNTest{
} }
func TestExpNNN(t *testing.T) { func TestExpNN(t *testing.T) {
for i, test := range expNNNTests { for i, test := range expNNTests {
x, _, _ := scanN(nil, test.x, 0) x, _, _ := nat(nil).scan(test.x, 0)
y, _, _ := scanN(nil, test.y, 0) y, _, _ := nat(nil).scan(test.y, 0)
out, _, _ := scanN(nil, test.out, 0) out, _, _ := nat(nil).scan(test.out, 0)
var m []Word var m nat
if len(test.m) > 0 { if len(test.m) > 0 {
m, _, _ = scanN(nil, test.m, 0) m, _, _ = nat(nil).scan(test.m, 0)
} }
z := expNNN(nil, x, y, m) z := nat(nil).expNN(x, y, m)
if cmpNN(z, out) != 0 { if z.cmp(out) != 0 {
t.Errorf("#%d got %v want %v", i, z, out) t.Errorf("#%d got %v want %v", i, z, out)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment