]> Cypherpunks repositories - gostls13.git/commitdiff
snapshot:
authorRobert Griesemer <gri@golang.org>
Sat, 15 Aug 2009 18:43:54 +0000 (11:43 -0700)
committerRobert Griesemer <gri@golang.org>
Sat, 15 Aug 2009 18:43:54 +0000 (11:43 -0700)
- renamed Z -> Int
- made Int ops methods on *Int
- "install" assembly routines dynamically
- replace mulVW functions with mulAddVWW
  of equivalent performance but symmetric functionality
  to divWVW
- implemented scanN

status:
- need mulNN (trivial)
- need division/modulo after which the set of
  elementary operations is complete
- to/from string conversion working

R=rsc
DELTA=320  (124 added, 50 deleted, 146 changed)
OCL=33308
CL=33341

src/pkg/big/arith.go
src/pkg/big/arith_amd64.s
src/pkg/big/arith_test.go
src/pkg/big/bigN.go
src/pkg/big/bigN_test.go
src/pkg/big/bigZ.go
src/pkg/big/bigZ_test.go

index 45b7a0cb259ecea14f0f97f1b8ae8f86c47cb1a1..f18b86509826f0dda816120c850d24869eec7f86 100644 (file)
@@ -13,11 +13,13 @@ import "unsafe"
 
 // ----------------------------------------------------------------------------
 // Elementary operations on words
+//
+// These operations are used by the vector operations below.
 
 func addWW_s(x, y, c Word) (z1, z0 Word)
 
 // z1<<_W + z0 = x+y+c, with c == 0 or 1
-func addWW(x, y, c Word) (z1, z0 Word) {
+func addWW_g(x, y, c Word) (z1, z0 Word) {
        yc := y+c;
        z0 = x+yc;
        if z0 < x || yc < y {
@@ -30,7 +32,7 @@ func addWW(x, y, c Word) (z1, z0 Word) {
 func subWW_s(x, y, c Word) (z1, z0 Word)
 
 // z1<<_W + z0 = x-y-c, with c == 0 or 1
-func subWW(x, y, c Word) (z1, z0 Word) {
+func subWW_g(x, y, c Word) (z1, z0 Word) {
        yc := y+c;
        z0 = x-yc;
        if z0 > x || yc < y {
@@ -40,8 +42,12 @@ func subWW(x, y, c Word) (z1, z0 Word) {
 }
 
 
+// TODO(gri) mulWW_g is not needed anymore. Keep around for
+//           now since mulAddWWW_g should use some of the
+//           optimizations from mulWW_g eventually.
+
 // z1<<_W + z0 = x*y
-func mulW(x, y Word) (z1, z0 Word) {
+func mulWW_g(x, y Word) (z1, z0 Word) {
        // Split x and y into 2 halfWords each, multiply
        // the halfWords separately while avoiding overflow,
        // and return the product as 2 Words.
@@ -96,7 +102,7 @@ func mulW(x, y Word) (z1, z0 Word) {
 
 
 // z1<<_W + z0 = x*y + c
-func mulAddWW(x, y, c Word) (z1, z0 Word) {
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
        // Split x and y into 2 halfWords each, multiply
        // the halfWords separately while avoiding overflow,
        // and return the product as 2 Words.
@@ -124,17 +130,17 @@ func mulAddWW(x, y, c Word) (z1, z0 Word) {
 }
 
 
-func divWW_s(x1, x0, y Word) (q, r Word)
+func divWWW_s(x1, x0, y Word) (q, r Word)
 
 // q = (x1<<_W + x0 - r)/y
-func divWW(x1, x0, y Word) (q, r Word) {
+func divWW_g(x1, x0, y Word) (q, r Word) {
        if x1 == 0 {
                q, r = x0/y, x0%y;
                return;
        }
 
        // TODO(gri) implement general case w/o assembly code
-       q, r = divWW_s(x1, x0, y);
+       q, r = divWWW_s(x1, x0, y);
        return;
 }
 
@@ -142,98 +148,105 @@ func divWW(x1, x0, y Word) (q, r Word) {
 // ----------------------------------------------------------------------------
 // Elementary operations on vectors
 
-// For each function f there is a corresponding function f_s which
-// implements the same functionality as f but is written in assembly.
+// All higher-level functions use these elementary vector operations.
+// The function pointers f are initialized with default implementations
+// f_g, written in Go for portability. The corresponding assembly routines
+// f_s should be installed if they exist.
+var (
+       // addVV sets z and returns c such that z+c = x+y.
+       addVV func(z, x, y *Word, n int) (c Word)       = addVV_g;
 
+       // subVV sets z and returns c such that z-c = x-y.
+       subVV func(z, x, y *Word, n int) (c Word)       = subVV_g;
 
-func addVV_s(z, x, y *Word, n int) (c Word)
+       // addVW sets z and returns c such that z+c = x-y.
+       addVW func(z, x *Word, y Word, n int) (c Word)  = addVW_g;
+
+       // subVW sets z and returns c such that z-c = x-y.
+       subVW func(z, x *Word, y Word, n int) (c Word)  = subVW_g;
+
+       // mulAddVWW sets z and returns c such that z+c = x*y + r.
+       mulAddVWW func(z, x *Word, y, r Word, n int) (c Word)   = mulAddVWW_g;
+
+       // divWVW sets z and returns r such that z-r = (xn<<(n*_W) + x) / y.
+       divWVW func(z* Word, xn Word, x *Word, y Word, n int) (r Word)  = divWVW_g;
+)
+
+
+func useAsm() bool
+
+func init() {
+       if useAsm() {
+               // Install assemby routines.
+               // TODO(gri) This should only be done if the assembly routines are present.
+               addVV = addVV_s;
+               subVV = subVV_s;
+               addVW = addVW_s;
+               subVW = subVW_s;
+               mulAddVWW = mulAddVWW_s;
+               divWVW = divWVW_s;
+       }
+}
+
+
+func (p *Word) at(i int) *Word {
+       return (*Word)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(i)*_S));
+}
 
-// addVV sets z and returns c such that z+c = x+y.
-// z, x, y are n-word vectors.
-func addVV(z, x, y *Word, n int) (c Word) {
-       for i := 0; i < n; i++ {
-               c, *z = addWW(*x, *y, c);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + _S)));
-               y = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(y)) + _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + _S)));
 
+func addVV_s(z, x, y *Word, n int) (c Word)
+func addVV_g(z, x, y *Word, n int) (c Word) {
+       for i := 0; i < n; i++ {
+               c, *z.at(i) = addWW_g(*x.at(i), *y.at(i), c);
        }
        return
 }
 
 
 func subVV_s(z, x, y *Word, n int) (c Word)
-
-// subVV sets z and returns c such that z-c = x-y.
-// z, x, y are n-word vectors.
-func subVV(z, x, y *Word, n int) (c Word) {
+func subVV_g(z, x, y *Word, n int) (c Word) {
        for i := 0; i < n; i++ {
-               c, *z = subWW(*x, *y, c);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + _S)));
-               y = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(y)) + _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + _S)));
+               c, *z.at(i) = subWW_g(*x.at(i), *y.at(i), c);
        }
        return
 }
 
 
 func addVW_s(z, x *Word, y Word, n int) (c Word)
-
-// addVW sets z and returns c such that z+c = x-y.
-// z, x are n-word vectors.
-func addVW(z, x *Word, y Word, n int) (c Word) {
+func addVW_g(z, x *Word, y Word, n int) (c Word) {
        c = y;
        for i := 0; i < n; i++ {
-               c, *z = addWW(*x, c, 0);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + _S)));
-
+               c, *z.at(i) = addWW_g(*x.at(i), c, 0);
        }
        return
 }
 
-func subVW_s(z, x *Word, y Word, n int) (c Word)
 
-// subVW sets z and returns c such that z-c = x-y.
-// z, x are n-word vectors.
-func subVW(z, x *Word, y Word, n int) (c Word) {
+func subVW_s(z, x *Word, y Word, n int) (c Word)
+func subVW_g(z, x *Word, y Word, n int) (c Word) {
        c = y;
        for i := 0; i < n; i++ {
-               c, *z = subWW(*x, c, 0);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + _S)));
-
+               c, *z.at(i) = subWW_g(*x.at(i), c, 0);
        }
        return
 }
 
 
-func mulVW_s(z, x *Word, y Word, n int) (c Word)
-
-// mulVW sets z and returns c such that z+c = x*y.
-// z, x are n-word vectors.
-func mulVW(z, x *Word, y Word, n int) (c Word) {
+func mulAddVWW_s(z, x *Word, y, r Word, n int) (c Word)
+func mulAddVWW_g(z, x *Word, y, r Word, n int) (c Word) {
+       c = r;
        for i := 0; i < n; i++ {
-               c, *z = mulAddWW(*x, y, c);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + _S)));
+               c, *z.at(i) = mulAddWWW_g(*x.at(i), y, c);
        }
        return
 }
 
 
 func divWVW_s(z* Word, xn Word, x *Word, y Word, n int) (r Word)
-
-// divWVW sets z and returns r such that z-r = (xn<<(n*_W) + x) / y.
-// z, x are n-word vectors; xn is the extra word x[n] of x.
-func divWVW(z* Word, xn Word, x *Word, y Word, n int) (r Word) {
+func divWVW_g(z* Word, xn Word, x *Word, y Word, n int) (r Word) {
        r = xn;
-       x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) + uintptr(n-1)*_S)));
-       z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) + uintptr(n-1)*_S)));
        for i := n-1; i >= 0; i-- {
-               *z, r = divWW(r, *x, y);
-               x = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(x)) - _S)));
-               z = (*Word)(unsafe.Pointer((uintptr(unsafe.Pointer(z)) - _S)));
+               *z.at(i), r = divWW_g(r, *x.at(i), y);
        }
        return;
 }
index 0853846a7ec801d5ba117f6efd6dafb9cba285a1..768a85d48a5adb9cb440a43f0418324349cda6e1 100644 (file)
@@ -3,10 +3,11 @@
 // license that can be found in the LICENSE file.
 
 // This file provides fast assembly versions of the routines in arith.go.
-//
-// Note: Eventually, these functions should be named like their corresponding
-//       Go implementations. For now their names have "_s" appended so that
-//       they can be linked and tested together.
+
+TEXT big·useAsm(SB),7,$0
+       MOVB $1, 8(SP)
+       RET
+
 
 // ----------------------------------------------------------------------------
 // Elementary operations on words
@@ -39,21 +40,10 @@ TEXT big·subWW_s(SB),7,$0
        RET
 
 
-// func mulWW_s(x, y Word) (z1, z0 Word)
-// z1<<64 + z0 = x*y
-//
-TEXT big·mulWW_s(SB),7,$0
-       MOVQ a+0(FP), AX
-       MULQ a+8(FP)
-       MOVQ DX, a+16(FP)
-       MOVQ AX, a+24(FP)
-       RET
-
-
-// func mulAddWW_s(x, y, c Word) (z1, z0 Word)
+// func mulAddWWW_s(x, y, c Word) (z1, z0 Word)
 // z1<<64 + z0 = x*y + c
 //
-TEXT big·mulAddWW_s(SB),7,$0
+TEXT big·mulAddWWW_s(SB),7,$0
        MOVQ a+0(FP), AX
        MULQ a+8(FP)
        ADDQ a+16(FP), AX
@@ -63,10 +53,10 @@ TEXT big·mulAddWW_s(SB),7,$0
        RET
 
 
-// func divWW_s(x1, x0, y Word) (q, r Word)
+// func divWWW_s(x1, x0, y Word) (q, r Word)
 // q = (x1<<64 + x0)/y + r
 //
-TEXT big·divWW_s(SB),7,$0
+TEXT big·divWWW_s(SB),7,$0
        MOVQ a+0(FP), DX
        MOVQ a+8(FP), AX
        DIVQ a+16(FP)
@@ -174,17 +164,17 @@ E4:       CMPQ BX, R11            // i < n
        RET
 
 
-// func mulVW_s(z, x *Word, y Word, n int) (c Word)
-TEXT big·mulVW_s(SB),7,$0
+// func mulAddVWW_s(z, x *Word, y, r Word, n int) (c Word)
+TEXT big·mulAddVWW_s(SB),7,$0
        MOVQ a+0(FP), R10       // z
        MOVQ a+8(FP), R8        // x
        MOVQ a+16(FP), R9       // y
-       MOVL a+24(FP), R11      // n
+       MOVQ a+24(FP), CX       // c = r
+       MOVL a+32(FP), R11      // n
        XORQ BX, BX                     // i = 0
-       XORQ CX, CX                     // c = 0
-       JMP E5
+       JMP E6
 
-L5:    MOVQ (R8)(BX*8), AX
+L6:    MOVQ (R8)(BX*8), AX
        MULQ R9
        ADDQ CX, AX
        ADCQ $0, DX
@@ -192,10 +182,10 @@ L5:       MOVQ (R8)(BX*8), AX
        MOVQ DX, CX
        ADDL $1, BX                     // i++
 
-E5:    CMPQ BX, R11            // i < n
-       JL L5
+E6:    CMPQ BX, R11            // i < n
+       JL L6
 
-       MOVQ CX, a+32(FP)       // return c
+       MOVQ CX, a+40(FP)       // return c
        RET
 
 
@@ -206,14 +196,14 @@ TEXT big·divWVW_s(SB),7,$0
        MOVQ a+16(FP), R8       // x
        MOVQ a+24(FP), R9       // y
        MOVL a+32(FP), BX       // i = n
-       JMP E6
+       JMP E7
 
-L6:    MOVQ (R8)(BX*8), AX
+L7:    MOVQ (R8)(BX*8), AX
        DIVQ R9
        MOVQ AX, (R10)(BX*8)
 
-E6:    SUBL $1, BX
-       JGE L6
+E7:    SUBL $1, BX                     // i--
+       JGE L7                          // i >= 0
 
        MOVQ DX, a+40(FP)       // return r
        RET
index 0544fa7c6242f67bf3113a2897d9dc7b2337e77a..f8e582e17c3bf986985d75e8cef592f382d6ce21 100644 (file)
@@ -36,19 +36,19 @@ func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
 func TestFunWW(t *testing.T) {
        for _, a := range sumWW {
                arg := a;
-               testFunWW(t, "addWW", addWW, arg);
+               testFunWW(t, "addWW_g", addWW_g, arg);
                testFunWW(t, "addWW_s", addWW_s, arg);
 
                arg = argWW{a.y, a.x, a.c, a.z1, a.z0};
-               testFunWW(t, "addWW symmetric", addWW, arg);
+               testFunWW(t, "addWW_g symmetric", addWW_g, arg);
                testFunWW(t, "addWW_s symmetric", addWW_s, arg);
 
                arg = argWW{a.z0, a.x, a.c, a.z1, a.y};
-               testFunWW(t, "subWW", subWW, arg);
+               testFunWW(t, "subWW_g", subWW_g, arg);
                testFunWW(t, "subWW_s", subWW_s, arg);
 
                arg = argWW{a.z0, a.y, a.c, a.z1, a.x};
-               testFunWW(t, "subWW symmetric", subWW, arg);
+               testFunWW(t, "subWW_g symmetric", subWW_g, arg);
                testFunWW(t, "subWW_s symmetric", subWW_s, arg);
        }
 }
@@ -97,19 +97,19 @@ func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
 func TestFunVV(t *testing.T) {
        for _, a := range sumVV {
                arg := a;
-               testFunVV(t, "addVV", addVV, arg);
+               testFunVV(t, "addVV_g", addVV_g, arg);
                testFunVV(t, "addVV_s", addVV_s, arg);
 
                arg = argVV{a.z, a.y, a.x, a.c};
-               testFunVV(t, "addVV symmetric", addVV, arg);
+               testFunVV(t, "addVV_g symmetric", addVV_g, arg);
                testFunVV(t, "addVV_s symmetric", addVV_s, arg);
 
                arg = argVV{a.x, a.z, a.y, a.c};
-               testFunVV(t, "subVV", subVV, arg);
+               testFunVV(t, "subVV_g", subVV_g, arg);
                testFunVV(t, "subVV_s", subVV_s, arg);
 
                arg = argVV{a.y, a.z, a.x, a.c};
-               testFunVV(t, "subVV symmetric", subVV, arg);
+               testFunVV(t, "subVV_g symmetric", subVV_g, arg);
                testFunVV(t, "subVV_s symmetric", subVV_s, arg);
        }
 }
@@ -162,26 +162,64 @@ func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
 func TestFunVW(t *testing.T) {
        for _, a := range sumVW {
                arg := a;
-               testFunVW(t, "addVW", addVW, arg);
+               testFunVW(t, "addVW_g", addVW_g, arg);
                testFunVW(t, "addVW_s", addVW_s, arg);
 
                arg = argVW{a.x, a.z, a.y, a.c};
-               testFunVW(t, "subVW", subVW, arg);
+               testFunVW(t, "subVW_g", subVW_g, arg);
                testFunVW(t, "subVW_s", subVW_s, arg);
        }
+}
 
-       for _, a := range prodVW {
-               arg := a;
-               testFunVW(t, "mulVW", mulVW, arg);
-               testFunVW(t, "mulVW_s", mulVW_s, arg);
+
+type funVWW func(z, x *Word, y, r Word, n int) (c Word)
+type argVWW struct { z, x []Word; y, r Word; c Word }
+
+var prodVWW = []argVWW{
+       argVWW{},
+       argVWW{[]Word{0}, []Word{0}, 0, 0, 0},
+       argVWW{[]Word{991}, []Word{0}, 0, 991, 0},
+       argVWW{[]Word{0}, []Word{_M}, 0, 0, 0},
+       argVWW{[]Word{991}, []Word{_M}, 0, 991, 0},
+       argVWW{[]Word{0}, []Word{0}, _M, 0, 0},
+       argVWW{[]Word{991}, []Word{0}, _M, 991, 0},
+       argVWW{[]Word{1}, []Word{1}, 1, 0, 0},
+       argVWW{[]Word{992}, []Word{1}, 1, 991, 0},
+       argVWW{[]Word{22793}, []Word{991}, 23, 0, 0},
+       argVWW{[]Word{22800}, []Word{991}, 23, 7, 0},
+       argVWW{[]Word{0, 0, 0, 22793}, []Word{0, 0, 0, 991}, 23, 0, 0},
+       argVWW{[]Word{7, 0, 0, 22793}, []Word{0, 0, 0, 991}, 23, 7, 0},
+       argVWW{[]Word{0, 0, 0, 0}, []Word{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+       argVWW{[]Word{991, 0, 0, 0}, []Word{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+       argVWW{[]Word{0, 0, 0, 0}, []Word{0, 0, 0, 0}, 894375984, 0, 0},
+       argVWW{[]Word{991, 0, 0, 0}, []Word{0, 0, 0, 0}, 894375984, 991, 0},
+       argVWW{[]Word{_M<<1&_M}, []Word{_M}, 1<<1, 0, _M>>(_W-1)},
+       argVWW{[]Word{_M<<1&_M + 1}, []Word{_M}, 1<<1, 1, _M>>(_W-1)},
+       argVWW{[]Word{_M<<7&_M}, []Word{_M}, 1<<7, 0, _M>>(_W-7)},
+       argVWW{[]Word{_M<<7&_M + 1<<6}, []Word{_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{[]Word{_M<<7&_M + 1<<6, _M, _M, _M}, []Word{_M, _M, _M, _M}, 1<<7, 1<<6, _M>>(_W-7)},
+}
+
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+       n := len(a.z);
+       z := make([]Word, n);
+       c := f(addr(z), addr(a.x), a.y, a.r, n);
+       for i, zi := range z {
+               if zi != a.z[i] {
+                       t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i]);
+                       break;
+               }
+       }
+       if c != a.c {
+               t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c);
        }
 }
 
 
-// TODO(gri) Vector mul and div are not quite symmetric.
-//           make it symmetric, mulVW should become mulAddVWW.
-//           Correct decision may become obvious after implementing
-//           the higher-level routines.
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+//           their signature is not symmetric. Try to unify.
 
 type funWVW func(z* Word, xn Word, x *Word, y Word, n int) (r Word)
 type argWVW struct { z []Word; xn Word; x []Word; y Word; r Word }
@@ -203,10 +241,14 @@ func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
 
 
 func TestFunVWW(t *testing.T) {
-       for _, a := range prodVW {
-               if a.y != 0 {
-                       arg := argWVW{a.x, a.c, a.z, a.y, 0};
-                       testFunWVW(t, "divWVW", divWVW, arg);
+       for _, a := range prodVWW {
+               arg := a;
+               testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg);
+               testFunVWW(t, "mulAddVWW_s", mulAddVWW_s, arg);
+
+               if a.y != 0 && a.r < a.y {
+                       arg := argWVW{a.x, a.c, a.z, a.y, a.r};
+                       testFunWVW(t, "divWVW_g", divWVW_g, arg);
                        testFunWVW(t, "divWVW_s", divWVW_s, arg);
                }
        }
index 50d73a79162cbad9d9d3919d4fa90e1b7bc00ca5..b696563095e3486d15272446751785d27e76a7a0 100644 (file)
@@ -20,6 +20,9 @@ package big
 // always normalized before returning the final result. The normalized
 // representation of 0 is the empty or nil slice (length = 0).
 
+// TODO(gri) - convert these routines into methods for type 'nat'
+//           - decide if type 'nat' should be exported
+
 func normN(z []Word) []Word {
        i := len(z);
        for i > 0 && z[i-1] == 0 {
@@ -45,7 +48,7 @@ func makeN(z []Word, m int) []Word {
 
 func newN(z []Word, x uint64) []Word {
        if x == 0 {
-               return nil;  // len == 0
+               return makeN(z, 0);
        }
 
        // single-digit values
@@ -95,6 +98,7 @@ func addNN(z, x, y []Word) []Word {
                // result is x
                return setN(z, x);
        }
+       // m > 0
 
        z = makeN(z, m);
        c := addVV(&z[0], &x[0], &y[0], n);
@@ -124,6 +128,7 @@ func subNN(z, x, y []Word) []Word {
                // result is x
                return setN(z, x);
        }
+       // m > 0
 
        z = makeN(z, m);
        c := subVV(&z[0], &x[0], &y[0], n);
@@ -133,8 +138,8 @@ func subNN(z, x, y []Word) []Word {
        if c != 0 {
                panic("underflow");
        }
-
        z = normN(z);
+
        return z;
 }
 
@@ -160,27 +165,38 @@ func cmpNN(x, y []Word) int {
 }
 
 
-func mulNW(z, x []Word, y Word) []Word {
+func mulAddNWW(z, x []Word, y, r Word) []Word {
        m := len(x);
-       switch {
-       case m == 0 || y == 0:
-               return setN(z, nil);  // result is 0
-       case y == 1:
-               return setN(z, x);  // result is x
+       if m == 0 || y == 0 {
+               return newN(z, uint64(r));      // result is r
        }
        // m > 0
-       z = makeN(z, m+1);
-       c := mulVW(&z[0], &x[0], y, m);
+
+       z = makeN(z, m);
+       c := mulAddVWW(&z[0], &x[0], y, r, m);
        if c > 0 {
                z = z[0 : m+1];
                z[m] = c;
        }
+
        return z;
 }
 
 
 func mulNN(z, x, y []Word) []Word {
+       m := len(x);
+       n := len(y);
+
+       switch {
+       case m < n:
+               return mulNN(z, x, y);
+       case m == 0 || n == 0:
+               return makeN(z, 0);
+       }
+       // m > 0 && n > 0 && m >= n
+
        panic("mulNN unimplemented");
+
        return z
 }
 
@@ -274,7 +290,7 @@ func scanN(z []Word, s string, base int) ([]Word, int, int) {
        for ; i < n; i++ {
                d := hexValue(s[i]);
                if 0 <= d && d < base {
-                       panic("scanN needs mulAddVWW");
+                       z = mulAddNWW(z, z, Word(base), Word(d));
                } else {
                        break;
                }
index 48b78c48b68e45ce058dc06d74b463cd7593b27b..8f9f9cc6a3e34d76ed08108eacc4afb87445a28c 100644 (file)
@@ -73,5 +73,16 @@ func TestStringN(t *testing.T) {
                if 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);
+               if cmpNN(x, a.x) != 0 {
+                       t.Errorf("scanN%+v\n\tgot z = %v; want %v", a, x, a.x);
+               }
+               if b != a.b {
+                       t.Errorf("scanN%+v\n\tgot b = %d; want %d", a, b, a.b);
+               }
+               if n != len(a.s) {
+                       t.Errorf("scanN%+v\n\tgot n = %d; want %d", a, n, len(a.s));
+               }
        }
 }
index 03534eccfda80a6bc7f2fc209bcd71f9c82d5f9f..3e6bbd15e88616fbddcd96b689da48664a179c66 100644 (file)
 
 package big
 
-// A Z represents a signed multi-precision integer.
-// The zero value for a Z represents the value 0.
-type Z struct {
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
        neg bool;  // sign
-       m []Word;  // mantissa
+       abs []Word;  // absolute value of the integer
 }
 
 
-// NewZ sets z to x.
-func NewZ(z Z, x int64) Z {
+// New sets z to x.
+func (z *Int) New(x int64) *Int {
        z.neg = false;
        if x < 0 {
                z.neg = true;
                x = -x;
        }
-       z.m = newN(z.m, uint64(x));
+       z.abs = newN(z.abs, uint64(x));
        return z;
 }
 
 
-// SetZ sets z to x.
-func SetZ(z, x Z) Z {
+// Set sets z to x.
+func (z *Int) Set(x *Int) *Int {
        z.neg = x.neg;
-       z.m = setN(z.m, x.m);
+       z.abs = setN(z.abs, x.abs);
        return z;
 }
 
 
-// AddZZ computes z = x+y.
-func AddZZ(z, x, y Z) Z {
+// Add computes z = x+y.
+func (z *Int) Add(x, y *Int) *Int {
        if x.neg == y.neg {
                // x + y == x + y
                // (-x) + (-y) == -(x + y)
                z.neg = x.neg;
-               z.m = addNN(z.m, x.m, y.m);
+               z.abs = addNN(z.abs, x.abs, y.abs);
        } else {
                // x + (-y) == x - y == -(y - x)
                // (-x) + y == y - x == -(x - y)
-               if cmpNN(x.m, y.m) >= 0 {
+               if cmpNN(x.abs, y.abs) >= 0 {
                        z.neg = x.neg;
-                       z.m = subNN(z.m, x.m, y.m);
+                       z.abs = subNN(z.abs, x.abs, y.abs);
                } else {
                        z.neg = !x.neg;
-                       z.m = subNN(z.m, y.m, x.m);
+                       z.abs = subNN(z.abs, y.abs, x.abs);
                }
        }
-       if len(z.m) == 0 {
+       if len(z.abs) == 0 {
                z.neg = false;  // 0 has no sign
        }
        return z
 }
 
 
-// AddZZ computes z = x-y.
-func SubZZ(z, x, y Z) Z {
+// Sub computes z = x-y.
+func (z *Int) Sub(x, y *Int) *Int {
        if x.neg != y.neg {
                // x - (-y) == x + y
                // (-x) - y == -(x + y)
                z.neg = x.neg;
-               z.m = addNN(z.m, x.m, y.m);
+               z.abs = addNN(z.abs, x.abs, y.abs);
        } else {
                // x - y == x - y == -(y - x)
                // (-x) - (-y) == y - x == -(x - y)
-               if cmpNN(x.m, y.m) >= 0 {
+               if cmpNN(x.abs, y.abs) >= 0 {
                        z.neg = x.neg;
-                       z.m = subNN(z.m, x.m, y.m);
+                       z.abs = subNN(z.abs, x.abs, y.abs);
                } else {
                        z.neg = !x.neg;
-                       z.m = subNN(z.m, y.m, x.m);
+                       z.abs = subNN(z.abs, y.abs, x.abs);
                }
        }
-       if len(z.m) == 0 {
+       if len(z.abs) == 0 {
                z.neg = false;  // 0 has no sign
        }
        return z
 }
 
 
-// MulZZ computes z = x*y.
-func MulZZ(z, x, y Z) Z {
+// Mul computes z = x*y.
+func (z *Int) Mul(x, y *Int) *Int {
        // x * y == x * y
        // x * (-y) == -(x * y)
        // (-x) * y == -(x * y)
        // (-x) * (-y) == x * y
        z.neg = x.neg != y.neg;
-       z.m = mulNN(z.m, x.m, y.m);
+       z.abs = mulNN(z.abs, x.abs, y.abs);
        return z
 }
 
 
-// NegZ computes z = -x.
-func NegZ(z, x Z) Z {
-       z.neg = len(x.m) > 0 && !x.neg;  // 0 has no sign
-       z.m = setN(z.m, x.m);
+// Neg computes z = -x.
+func (z *Int) Neg(x *Int) *Int {
+       z.neg = len(x.abs) > 0 && !x.neg;  // 0 has no sign
+       z.abs = setN(z.abs, x.abs);
        return z;
 }
 
 
-// Cmp compares x and y. The result is an int value that is
+// CmpInt compares x and y. The result is an int value that is
 //
 //   <  0 if x <  y
 //   == 0 if x == y
 //   >  0 if x >  y
 //
-func CmpZZ(x, y Z) (r int) {
+func CmpInt(x, y *Int) (r int) {
        // x cmp y == x cmp y
        // x cmp (-y) == x
        // (-x) cmp y == y
        // (-x) cmp (-y) == -(x cmp y)
        switch {
        case x.neg == y.neg:
-               r = cmpNN(x.m, y.m);
+               r = cmpNN(x.abs, y.abs);
                if x.neg {
                        r = -r;
                }
@@ -130,10 +130,10 @@ func CmpZZ(x, y Z) (r int) {
 }
 
 
-func (x Z) String() string {
+func (x *Int) String() string {
        s := "";
        if x.neg {
                s = "-";
        }
-       return s + stringN(x.m, 10);
+       return s + stringN(x.abs, 10);
 }
index ed6f4ff9b7c19a8be84d5a0dd5540c18258c7dc2..528afdd2341ce53e6412fb889f5c16091cabb9c8 100644 (file)
@@ -7,14 +7,14 @@ package big
 import "testing"
 
 
-func newZ(x int64) Z {
-       var z Z;
-       return NewZ(z, x);
+func newZ(x int64) *Int {
+       var z Int;
+       return z.New(x);
 }
 
 
-type funZZ func(z, x, y Z) Z
-type argZZ struct { z, x, y Z }
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct { z, x, y *Int }
 
 var sumZZ = []argZZ{
        argZZ{newZ(0), newZ(0), newZ(0)},
@@ -28,9 +28,9 @@ var sumZZ = []argZZ{
 
 func TestSetZ(t *testing.T) {
        for _, a := range sumZZ {
-               var z Z;
-               z = SetZ(z, a.z);
-               if CmpZZ(z, a.z) != 0 {
+               var z Int;
+               z.Set(a.z);
+               if CmpInt(&z, a.z) != 0 {
                        t.Errorf("got z = %v; want %v", z, a.z);
                }
        }
@@ -38,15 +38,17 @@ func TestSetZ(t *testing.T) {
 
 
 func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
-       var z Z;
-       z = f(z, a.x, a.y);
-       if CmpZZ(z, a.z) != 0 {
-               t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z);
+       var z Int;
+       f(&z, a.x, a.y);
+       if CmpInt(&z, a.z) != 0 {
+               t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z);
        }
 }
 
 
 func TestFunZZ(t *testing.T) {
+       AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) };
+       SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) };
        for _, a := range sumZZ {
                arg := a;
                testFunZZ(t, "AddZZ", AddZZ, arg);