diff options
Diffstat (limited to 'src/pkg/big')
-rw-r--r-- | src/pkg/big/Makefile | 2 | ||||
-rw-r--r-- | src/pkg/big/arith.go | 228 | ||||
-rw-r--r-- | src/pkg/big/arith_arm.s | 289 | ||||
-rw-r--r-- | src/pkg/big/arith_test.go | 197 | ||||
-rwxr-xr-x | src/pkg/big/int.go | 69 | ||||
-rwxr-xr-x | src/pkg/big/int_test.go | 453 | ||||
-rwxr-xr-x | src/pkg/big/nat.go | 24 | ||||
-rwxr-xr-x | src/pkg/big/nat_test.go | 162 | ||||
-rw-r--r-- | src/pkg/big/rat.go | 136 | ||||
-rw-r--r-- | src/pkg/big/rat_test.go | 219 |
10 files changed, 1041 insertions, 738 deletions
diff --git a/src/pkg/big/Makefile b/src/pkg/big/Makefile index 7a4311dca..3d4b56d78 100644 --- a/src/pkg/big/Makefile +++ b/src/pkg/big/Makefile @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -include ../../Make.$(GOARCH) +include ../../Make.inc TARG=big GOFILES=\ diff --git a/src/pkg/big/arith.go b/src/pkg/big/arith.go index 29966c7bc..df3808f5e 100644 --- a/src/pkg/big/arith.go +++ b/src/pkg/big/arith.go @@ -56,161 +56,29 @@ func subWW_g(x, y, c Word) (z1, z0 Word) { // z1<<_W + z0 = x*y +// Adapted from Warren, Hacker's Delight, p. 132. 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. - - if x < y { - x, y = y, x - } - - if x < _B2 { - // y < _B2 because y <= x - // sub-digits of x and y are (0, x) and (0, y) - // z = z[0] = x*y - z0 = x * y - return - } - - if y < _B2 { - // sub-digits of x and y are (x1, x0) and (0, y) - // x = (x1*_B2 + x0) - // y = (y1*_B2 + y0) - x1, x0 := x>>_W2, x&_M2 - - // x*y = t2*_B2*_B2 + t1*_B2 + t0 - t0 := x0 * y - t1 := x1 * y - - // compute result digits but avoid overflow - // z = z[1]*_B + z[0] = x*y - z0 = t1<<_W2 + t0 - z1 = (t1 + t0>>_W2) >> _W2 - return - } - - // general case - // sub-digits of x and y are (x1, x0) and (y1, y0) - // x = (x1*_B2 + x0) - // y = (y1*_B2 + y0) - x1, x0 := x>>_W2, x&_M2 - y1, y0 := y>>_W2, y&_M2 - - // x*y = t2*_B2*_B2 + t1*_B2 + t0 - t0 := x0 * y0 - // t1 := x1*y0 + x0*y1; - var c Word - t1 := x1 * y0 - t1a := t1 - t1 += x0 * y1 - if t1 < t1a { - c++ - } - t2 := x1*y1 + c*_B2 - - // compute result digits but avoid overflow - // z = z[1]*_B + z[0] = x*y - // This may overflow, but that's ok because we also sum t1 and t0 above - // and we take care of the overflow there. - z0 = t1<<_W2 + t0 - - // z1 = t2 + (t1 + t0>>_W2)>>_W2; - var c3 Word - z1 = t1 + t0>>_W2 - if z1 < t1 { - c3++ - } - z1 >>= _W2 - z1 += c3 * _B2 - z1 += t2 + x0 := x & _M2 + x1 := x >> _W2 + y0 := y & _M2 + y1 := y >> _W2 + w0 := x0 * y0 + t := x1*y0 + w0>>_W2 + w1 := t & _M2 + w2 := t >> _W2 + w1 += x0 * y1 + z1 = x1*y1 + w2 + w1>>_W2 + z0 = x * y return } // z1<<_W + z0 = x*y + c 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. - - // TODO(gri) Should implement special cases for faster execution. - - // general case - // sub-digits of x, y, and c are (x1, x0), (y1, y0), (c1, c0) - // x = (x1*_B2 + x0) - // y = (y1*_B2 + y0) - x1, x0 := x>>_W2, x&_M2 - y1, y0 := y>>_W2, y&_M2 - c1, c0 := c>>_W2, c&_M2 - - // x*y + c = t2*_B2*_B2 + t1*_B2 + t0 - // (1<<32-1)^2 == 1<<64 - 1<<33 + 1, so there's space to add c0 in here. - t0 := x0*y0 + c0 - - // t1 := x1*y0 + x0*y1 + c1; - var c2 Word // extra carry - t1 := x1*y0 + c1 - t1a := t1 - t1 += x0 * y1 - if t1 < t1a { // If the number got smaller then we overflowed. - c2++ + z1, zz0 := mulWW(x, y) + if z0 = zz0 + c; z0 < zz0 { + z1++ } - - t2 := x1*y1 + c2*_B2 - - // compute result digits but avoid overflow - // z = z[1]*_B + z[0] = x*y - // z0 = t1<<_W2 + t0; - // This may overflow, but that's ok because we also sum t1 and t0 below - // and we take care of the overflow there. - z0 = t1<<_W2 + t0 - - var c3 Word - z1 = t1 + t0>>_W2 - if z1 < t1 { - c3++ - } - z1 >>= _W2 - z1 += t2 + c3*_B2 - - return -} - - -// q = (x1<<_W + x0 - r)/y -// The most significant bit of y must be 1. -func divStep(x1, x0, y Word) (q, r Word) { - d1, d0 := y>>_W2, y&_M2 - q1, r1 := x1/d1, x1%d1 - m := q1 * d0 - r1 = r1*_B2 | x0>>_W2 - if r1 < m { - q1-- - r1 += y - if r1 >= y && r1 < m { - q1-- - r1 += y - } - } - r1 -= m - - r0 := r1 % d1 - q0 := r1 / d1 - m = q0 * d0 - r0 = r0*_B2 | x0&_M2 - if r0 < m { - q0-- - r0 += y - if r0 >= y && r0 < m { - q0-- - r0 += y - } - } - r0 -= m - - q = q1*_B2 | q0 - r = r0 return } @@ -241,46 +109,48 @@ func leadingZeros(x Word) uint { } -// q = (x1<<_W + x0 - r)/y -func divWW_g(x1, x0, y Word) (q, r Word) { - if x1 == 0 { - q, r = x0/y, x0%y - return +// q = (u1<<_W + u0 - r)/y +// Adapted from Warren, Hacker's Delight, p. 152. +func divWW_g(u1, u0, v Word) (q, r Word) { + if u1 >= v { + return 1<<_W - 1, 1<<_W - 1 } - var q0, q1 Word - z := leadingZeros(y) - if y > x1 { - if z != 0 { - y <<= z - x1 = (x1 << z) | (x0 >> (_W - z)) - x0 <<= z - } - q0, x0 = divStep(x1, x0, y) - q1 = 0 - } else { - if z == 0 { - x1 -= y - q1 = 1 - } else { - z1 := _W - z - y <<= z - x2 := x1 >> z1 - x1 = (x1 << z) | (x0 >> z1) - x0 <<= z - q1, x1 = divStep(x2, x1, y) - } + s := leadingZeros(v) + v <<= s + + vn1 := v >> _W2 + vn0 := v & _M2 + un32 := u1<<s | u0>>(_W-s) + un10 := u0 << s + un1 := un10 >> _W2 + un0 := un10 & _M2 + q1 := un32 / vn1 + rhat := un32 - q1*vn1 - q0, x0 = divStep(x1, x0, y) +again1: + if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 { + q1-- + rhat += vn1 + if rhat < _B2 { + goto again1 + } } - r = x0 >> z + un21 := un32*_B2 + un1 - q1*v + q0 := un21 / vn1 + rhat = un21 - q0*vn1 - if q1 != 0 { - panic("div out of range") +again2: + if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 { + q0-- + rhat += vn1 + if rhat < _B2 { + goto again2 + } } - return q0, r + return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s } diff --git a/src/pkg/big/arith_arm.s b/src/pkg/big/arith_arm.s index c8a45efc4..e4a9a962c 100644 --- a/src/pkg/big/arith_arm.s +++ b/src/pkg/big/arith_arm.s @@ -5,31 +5,302 @@ // This file provides fast assembly versions for the elementary // arithmetic operations on vectors implemented in arith.go. -// TODO(gri) Implement these routines. +#define CFLAG 29 // bit position of carry flag + +// func addVV(z, x, y []Word) (c Word) TEXT ·addVV(SB),7,$0 - B ·addVV_g(SB) + MOVW $0, R0 + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW n+4(FP), R4 + MOVW R4<<2, R4 + ADD R1, R4 + B E1 +L1: + MOVW.P 4(R2), R5 + MOVW.P 4(R3), R6 + MOVW R0, CPSR + ADC.S R6, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 +E1: + CMP R1, R4 + BNE L1 + + MOVW R0>>CFLAG, R0 + AND $1, R0 + MOVW R0, c+36(FP) + RET + +// func subVV(z, x, y []Word) (c Word) +// (same as addVV except for SBC instead of ADC and label names) TEXT ·subVV(SB),7,$0 - B ·subVV_g(SB) + MOVW $(1<<CFLAG), R0 + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW n+4(FP), R4 + MOVW R4<<2, R4 + ADD R1, R4 + B E2 +L2: + MOVW.P 4(R2), R5 + MOVW.P 4(R3), R6 + MOVW R0, CPSR + SBC.S R6, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 +E2: + CMP R1, R4 + BNE L2 + + MOVW R0>>CFLAG, R0 + AND $1, R0 + EOR $1, R0 + MOVW R0, c+36(FP) + RET + +// func addVW(z, x []Word, y Word) (c Word) TEXT ·addVW(SB),7,$0 - B ·addVW_g(SB) + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW n+4(FP), R4 + MOVW R4<<2, R4 + ADD R1, R4 + CMP R1, R4 + BNE L3a + MOVW R3, c+28(FP) + RET +L3a: + MOVW.P 4(R2), R5 + ADD.S R3, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 + B E3 +L3: + MOVW.P 4(R2), R5 + MOVW R0, CPSR + ADC.S $0, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 +E3: + CMP R1, R4 + BNE L3 + + MOVW R0>>CFLAG, R0 + AND $1, R0 + MOVW R0, c+28(FP) + RET + TEXT ·subVW(SB),7,$0 - B ·subVW_g(SB) + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW n+4(FP), R4 + MOVW R4<<2, R4 + ADD R1, R4 + CMP R1, R4 + BNE L4a + MOVW R3, c+28(FP) + RET +L4a: + MOVW.P 4(R2), R5 + SUB.S R3, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 + B E4 +L4: + MOVW.P 4(R2), R5 + MOVW R0, CPSR + SBC.S $0, R5 + MOVW.P R5, 4(R1) + MOVW CPSR, R0 +E4: + CMP R1, R4 + BNE L4 + + MOVW R0>>CFLAG, R0 + AND $1, R0 + EOR $1, R0 + MOVW R0, c+28(FP) + RET + +// func shlVW(z, x []Word, s Word) (c Word) TEXT ·shlVW(SB),7,$0 - B ·shlVW_g(SB) + MOVW n+4(FP), R5 + CMP $0, R5 + BEQ X7 + + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW R5<<2, R5 + ADD R5, R2 + ADD R1, R5 + MOVW s+24(FP), R3 + CMP $0, R3 // shift 0 is special + BEQ Y7 + ADD $4, R1 // stop one word early + MOVW $32, R4 + SUB R3, R4 + MOVW $0, R7 + + MOVW.W -4(R2), R6 + MOVW R6<<R3, R7 + MOVW R6>>R4, R6 + MOVW R6, c+28(FP) + B E7 + +L7: + MOVW.W -4(R2), R6 + ORR R6>>R4, R7 + MOVW.W R7, -4(R5) + MOVW R6<<R3, R7 +E7: + CMP R1, R5 + BNE L7 + + MOVW R7, -4(R5) + RET + +Y7: // copy loop, because shift 0 == shift 32 + MOVW.W -4(R2), R6 + MOVW.W R6, -4(R5) + CMP R1, R5 + BNE Y7 + +X7: + MOVW $0, R1 + MOVW R1, c+28(FP) + RET + TEXT ·shrVW(SB),7,$0 - B ·shrVW_g(SB) + MOVW n+4(FP), R5 + CMP $0, R5 + BEQ X6 + + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW R5<<2, R5 + ADD R1, R5 + MOVW s+24(FP), R3 + CMP $0, R3 // shift 0 is special + BEQ Y6 + SUB $4, R5 // stop one word early + MOVW $32, R4 + SUB R3, R4 + MOVW $0, R7 + + // first word + MOVW.P 4(R2), R6 + MOVW R6>>R3, R7 + MOVW R6<<R4, R6 + MOVW R6, c+28(FP) + B E6 + + // word loop +L6: + MOVW.P 4(R2), R6 + ORR R6<<R4, R7 + MOVW.P R7, 4(R1) + MOVW R6>>R3, R7 +E6: + CMP R1, R5 + BNE L6 + + MOVW R7, 0(R1) + RET + +Y6: // copy loop, because shift 0 == shift 32 + MOVW.P 4(R2), R6 + MOVW.P R6, 4(R1) + CMP R1, R5 + BNE Y6 + +X6: + MOVW $0, R1 + MOVW R1, c+28(FP) + RET + TEXT ·mulAddVWW(SB),7,$0 - B ·mulAddVWW_g(SB) + MOVW $0, R0 + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW r+28(FP), R4 + MOVW n+4(FP), R5 + MOVW R5<<2, R5 + ADD R1, R5 + B E8 + + // word loop +L8: + MOVW.P 4(R2), R6 + MULLU R6, R3, (R7, R6) + ADD.S R4, R6 + ADC R0, R7 + MOVW.P R6, 4(R1) + MOVW R7, R4 +E8: + CMP R1, R5 + BNE L8 + + MOVW R4, c+32(FP) + RET + TEXT ·addMulVVW(SB),7,$0 - B ·addMulVVW_g(SB) + MOVW $0, R0 + MOVW z+0(FP), R1 + MOVW x+12(FP), R2 + MOVW y+24(FP), R3 + MOVW n+4(FP), R5 + MOVW R5<<2, R5 + ADD R1, R5 + MOVW $0, R4 + B E9 + + // word loop +L9: + MOVW.P 4(R2), R6 + MULLU R6, R3, (R7, R6) + ADD.S R4, R6 + ADC R0, R7 + MOVW 0(R1), R4 + ADD.S R4, R6 + ADC R0, R7 + MOVW.P R6, 4(R1) + MOVW R7, R4 +E9: + CMP R1, R5 + BNE L9 + + MOVW R4, c+28(FP) + RET + TEXT ·divWVW(SB),7,$0 + // ARM has no multiword division, so use portable code. B ·divWVW_g(SB) + +TEXT ·divWW(SB),7,$0 + // ARM has no multiword division, so use portable code. + B ·divWW_g(SB) + + +// func mulWW(x, y Word) (z1, z0 Word) +TEXT ·mulWW(SB),7,$0 + MOVW x+0(FP), R1 + MOVW y+4(FP), R2 + MULLU R1, R2, (R4, R3) + MOVW R4, z1+8(FP) + MOVW R3, z0+12(FP) + RET diff --git a/src/pkg/big/arith_test.go b/src/pkg/big/arith_test.go index efdb65123..934b302df 100644 --- a/src/pkg/big/arith_test.go +++ b/src/pkg/big/arith_test.go @@ -13,17 +13,17 @@ type argWW struct { } var sumWW = []argWW{ - argWW{0, 0, 0, 0, 0}, - argWW{0, 1, 0, 0, 1}, - argWW{0, 0, 1, 0, 1}, - argWW{0, 1, 1, 0, 2}, - argWW{12345, 67890, 0, 0, 80235}, - argWW{12345, 67890, 1, 0, 80236}, - argWW{_M, 1, 0, 1, 0}, - argWW{_M, 0, 1, 1, 0}, - argWW{_M, 1, 1, 1, 1}, - argWW{_M, _M, 0, 1, _M - 1}, - argWW{_M, _M, 1, 1, _M}, + {0, 0, 0, 0, 0}, + {0, 1, 0, 0, 1}, + {0, 0, 1, 0, 1}, + {0, 1, 1, 0, 2}, + {12345, 67890, 0, 0, 80235}, + {12345, 67890, 1, 0, 80236}, + {_M, 1, 0, 1, 0}, + {_M, 0, 1, 1, 0}, + {_M, 1, 1, 1, 1}, + {_M, _M, 0, 1, _M - 1}, + {_M, _M, 1, 1, _M}, } @@ -59,15 +59,15 @@ type argVV struct { } var sumVV = []argVV{ - argVV{}, - argVV{nat{0}, nat{0}, nat{0}, 0}, - argVV{nat{1}, nat{1}, nat{0}, 0}, - argVV{nat{0}, nat{_M}, nat{1}, 1}, - argVV{nat{80235}, nat{12345}, nat{67890}, 0}, - argVV{nat{_M - 1}, nat{_M}, nat{_M}, 1}, - argVV{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1}, - argVV{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0}, - argVV{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1}, + {}, + {nat{0}, nat{0}, nat{0}, 0}, + {nat{1}, nat{1}, nat{0}, 0}, + {nat{0}, nat{_M}, nat{1}, 1}, + {nat{80235}, nat{12345}, nat{67890}, 0}, + {nat{_M - 1}, nat{_M}, nat{_M}, 1}, + {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1}, + {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0}, + {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1}, } @@ -115,57 +115,58 @@ type argVW struct { } var sumVW = []argVW{ - argVW{}, - argVW{nat{0}, nat{0}, 0, 0}, - argVW{nat{1}, nat{0}, 1, 0}, - argVW{nat{1}, nat{1}, 0, 0}, - argVW{nat{0}, nat{_M}, 1, 1}, - argVW{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1}, + {}, + {nil, nil, 2, 2}, + {nat{0}, nat{0}, 0, 0}, + {nat{1}, nat{0}, 1, 0}, + {nat{1}, nat{1}, 0, 0}, + {nat{0}, nat{_M}, 1, 1}, + {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1}, } var prodVW = []argVW{ - argVW{}, - argVW{nat{0}, nat{0}, 0, 0}, - argVW{nat{0}, nat{_M}, 0, 0}, - argVW{nat{0}, nat{0}, _M, 0}, - argVW{nat{1}, nat{1}, 1, 0}, - argVW{nat{22793}, nat{991}, 23, 0}, - argVW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0}, - argVW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0}, - argVW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0}, - argVW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)}, - argVW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)}, - argVW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)}, + {}, + {nat{0}, nat{0}, 0, 0}, + {nat{0}, nat{_M}, 0, 0}, + {nat{0}, nat{0}, _M, 0}, + {nat{1}, nat{1}, 1, 0}, + {nat{22793}, nat{991}, 23, 0}, + {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0}, + {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0}, + {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0}, + {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)}, + {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)}, + {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)}, } var lshVW = []argVW{ - argVW{}, - argVW{nat{0}, nat{0}, 0, 0}, - argVW{nat{0}, nat{0}, 1, 0}, - argVW{nat{0}, nat{0}, 20, 0}, - - argVW{nat{_M}, nat{_M}, 0, 0}, - argVW{nat{_M << 1 & _M}, nat{_M}, 1, 1}, - argVW{nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)}, - - argVW{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, - argVW{nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1}, - argVW{nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)}, + {}, + {nat{0}, nat{0}, 0, 0}, + {nat{0}, nat{0}, 1, 0}, + {nat{0}, nat{0}, 20, 0}, + + {nat{_M}, nat{_M}, 0, 0}, + {nat{_M << 1 & _M}, nat{_M}, 1, 1}, + {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)}, + + {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, + {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1}, + {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)}, } var rshVW = []argVW{ - argVW{}, - argVW{nat{0}, nat{0}, 0, 0}, - argVW{nat{0}, nat{0}, 1, 0}, - argVW{nat{0}, nat{0}, 20, 0}, - - argVW{nat{_M}, nat{_M}, 0, 0}, - argVW{nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M}, - argVW{nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M}, - - argVW{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, - argVW{nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M}, - argVW{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M}, + {}, + {nat{0}, nat{0}, 0, 0}, + {nat{0}, nat{0}, 1, 0}, + {nat{0}, nat{0}, 20, 0}, + + {nat{_M}, nat{_M}, 0, 0}, + {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M}, + {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M}, + + {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, + {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M}, + {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M}, } @@ -217,29 +218,29 @@ type argVWW struct { } var prodVWW = []argVWW{ - argVWW{}, - argVWW{nat{0}, nat{0}, 0, 0, 0}, - argVWW{nat{991}, nat{0}, 0, 991, 0}, - argVWW{nat{0}, nat{_M}, 0, 0, 0}, - argVWW{nat{991}, nat{_M}, 0, 991, 0}, - argVWW{nat{0}, nat{0}, _M, 0, 0}, - argVWW{nat{991}, nat{0}, _M, 991, 0}, - argVWW{nat{1}, nat{1}, 1, 0, 0}, - argVWW{nat{992}, nat{1}, 1, 991, 0}, - argVWW{nat{22793}, nat{991}, 23, 0, 0}, - argVWW{nat{22800}, nat{991}, 23, 7, 0}, - argVWW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0}, - argVWW{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0}, - argVWW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0}, - argVWW{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0}, - argVWW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0}, - argVWW{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0}, - argVWW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)}, - argVWW{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)}, - argVWW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)}, - argVWW{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, - argVWW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _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)}, + {}, + {nat{0}, nat{0}, 0, 0, 0}, + {nat{991}, nat{0}, 0, 991, 0}, + {nat{0}, nat{_M}, 0, 0, 0}, + {nat{991}, nat{_M}, 0, 991, 0}, + {nat{0}, nat{0}, _M, 0, 0}, + {nat{991}, nat{0}, _M, 991, 0}, + {nat{1}, nat{1}, 1, 0, 0}, + {nat{992}, nat{1}, 1, 991, 0}, + {nat{22793}, nat{991}, 23, 0, 0}, + {nat{22800}, nat{991}, 23, 7, 0}, + {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0}, + {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0}, + {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0}, + {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0}, + {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0}, + {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0}, + {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)}, + {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)}, + {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)}, + {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, + {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)}, + {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, } @@ -300,15 +301,12 @@ func TestFunVWW(t *testing.T) { } -type mulWWTest struct { +var mulWWTests = []struct { x, y Word q, r Word -} - - -var mulWWTests = []mulWWTest{ - mulWWTest{_M, _M, _M - 1, 1}, - // 32 bit only: mulWWTest{0xc47dfa8c, 50911, 0x98a4, 0x998587f4}, +}{ + {_M, _M, _M - 1, 1}, + // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4}, } @@ -322,18 +320,15 @@ func TestMulWW(t *testing.T) { } -type mulAddWWWTest struct { +var mulAddWWWTests = []struct { x, y, c Word q, r Word -} - - -var mulAddWWWTests = []mulAddWWWTest{ +}{ // TODO(agl): These will only work on 64-bit platforms. - // mulAddWWWTest{15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781}, - // mulAddWWWTest{15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382}, - mulAddWWWTest{_M, _M, 0, _M - 1, 1}, - mulAddWWWTest{_M, _M, _M, _M, 0}, + // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781}, + // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382}, + {_M, _M, 0, _M - 1, 1}, + {_M, _M, _M, _M, 0}, } diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go index 873d5b50c..46e008734 100755 --- a/src/pkg/big/int.go +++ b/src/pkg/big/int.go @@ -6,8 +6,10 @@ package big -import "fmt" - +import ( + "fmt" + "rand" +) // An Int represents a signed multi-precision integer. // The zero value for an Int represents the value 0. @@ -20,6 +22,23 @@ type Int struct { var intOne = &Int{false, natOne} +// Sign returns: +// +// -1 if x < 0 +// 0 if x == 0 +// +1 if x > 0 +// +func (x *Int) Sign() int { + if len(x.abs) == 0 { + return 0 + } + if x.neg { + return -1 + } + return 1 +} + + // SetInt64 sets z to x and returns z. func (z *Int) SetInt64(x int64) *Int { neg := false @@ -47,6 +66,14 @@ func (z *Int) Set(x *Int) *Int { } +// Abs sets z to |x| (the absolute value of x) and returns z. +func (z *Int) Abs(x *Int) *Int { + z.abs = z.abs.set(x.abs) + z.neg = false + return z +} + + // Neg sets z to -x and returns z. func (z *Int) Neg(x *Int) *Int { z.abs = z.abs.set(x.abs) @@ -347,10 +374,12 @@ func (z *Int) SetString(s string, base int) (*Int, bool) { return z, false } - neg := false - if s[0] == '-' { - neg = true + neg := s[0] == '-' + if neg || s[0] == '+' { s = s[1:] + if len(s) == 0 { + return z, false + } } var scanned int @@ -518,6 +547,18 @@ func ProbablyPrime(z *Int, n int) bool { } +// Rand sets z to a pseudo-random number in [0, n) and returns z. +func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int { + z.neg = false + if n.neg == true || len(n.abs) == 0 { + z.abs = nil + return z + } + z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen()) + return z +} + + // ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where // p is a prime) and returns z. func (z *Int) ModInverse(g, p *Int) *Int { @@ -563,7 +604,7 @@ func (z *Int) And(x, y *Int) *Int { if x.neg { // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1) x1 := nat{}.sub(x.abs, natOne) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.add(z.abs.or(x1, y1), natOne) z.neg = true // z cannot be zero if x and y are negative return z @@ -581,7 +622,7 @@ func (z *Int) And(x, y *Int) *Int { } // x & (-y) == x & ^(y-1) == x &^ (y-1) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.andNot(x.abs, y1) z.neg = false return z @@ -594,7 +635,7 @@ func (z *Int) AndNot(x, y *Int) *Int { if x.neg { // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1) x1 := nat{}.sub(x.abs, natOne) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.andNot(y1, x1) z.neg = false return z @@ -608,14 +649,14 @@ func (z *Int) AndNot(x, y *Int) *Int { if x.neg { // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1) - x1 := z.abs.sub(x.abs, natOne) + x1 := nat{}.sub(x.abs, natOne) z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne) z.neg = true // z cannot be zero if x is negative and y is positive return z } // x &^ (-y) == x &^ ^(y-1) == x & (y-1) - y1 := z.abs.add(y.abs, natOne) + y1 := nat{}.add(y.abs, natOne) z.abs = z.abs.and(x.abs, y1) z.neg = false return z @@ -628,7 +669,7 @@ func (z *Int) Or(x, y *Int) *Int { if x.neg { // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1) x1 := nat{}.sub(x.abs, natOne) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.add(z.abs.and(x1, y1), natOne) z.neg = true // z cannot be zero if x and y are negative return z @@ -646,7 +687,7 @@ func (z *Int) Or(x, y *Int) *Int { } // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne) z.neg = true // z cannot be zero if one of x or y is negative return z @@ -659,7 +700,7 @@ func (z *Int) Xor(x, y *Int) *Int { if x.neg { // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1) x1 := nat{}.sub(x.abs, natOne) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.xor(x1, y1) z.neg = false return z @@ -677,7 +718,7 @@ func (z *Int) Xor(x, y *Int) *Int { } // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1) - y1 := z.abs.sub(y.abs, natOne) + y1 := nat{}.sub(y.abs, natOne) z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne) z.neg = true // z cannot be zero if only one of x or y is negative return z diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go index 269c814d4..fc981e1da 100755 --- a/src/pkg/big/int_test.go +++ b/src/pkg/big/int_test.go @@ -29,24 +29,36 @@ type argZZ struct { var sumZZ = []argZZ{ - argZZ{NewInt(0), NewInt(0), NewInt(0)}, - argZZ{NewInt(1), NewInt(1), NewInt(0)}, - argZZ{NewInt(1111111110), NewInt(123456789), NewInt(987654321)}, - argZZ{NewInt(-1), NewInt(-1), NewInt(0)}, - argZZ{NewInt(864197532), NewInt(-123456789), NewInt(987654321)}, - argZZ{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)}, + {NewInt(0), NewInt(0), NewInt(0)}, + {NewInt(1), NewInt(1), NewInt(0)}, + {NewInt(1111111110), NewInt(123456789), NewInt(987654321)}, + {NewInt(-1), NewInt(-1), NewInt(0)}, + {NewInt(864197532), NewInt(-123456789), NewInt(987654321)}, + {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)}, } var prodZZ = []argZZ{ - argZZ{NewInt(0), NewInt(0), NewInt(0)}, - argZZ{NewInt(0), NewInt(1), NewInt(0)}, - argZZ{NewInt(1), NewInt(1), NewInt(1)}, - argZZ{NewInt(-991 * 991), NewInt(991), NewInt(-991)}, + {NewInt(0), NewInt(0), NewInt(0)}, + {NewInt(0), NewInt(1), NewInt(0)}, + {NewInt(1), NewInt(1), NewInt(1)}, + {NewInt(-991 * 991), NewInt(991), NewInt(-991)}, // TODO(gri) add larger products } +func TestSignZ(t *testing.T) { + var zero Int + for _, a := range sumZZ { + s := a.z.Sign() + e := a.z.Cmp(&zero) + if s != e { + t.Errorf("got %d; want %d for z = %v", s, e, a.z) + } + } +} + + func TestSetZ(t *testing.T) { for _, a := range sumZZ { var z Int @@ -61,11 +73,28 @@ func TestSetZ(t *testing.T) { } +func TestAbsZ(t *testing.T) { + var zero Int + for _, a := range sumZZ { + var z Int + z.Abs(a.z) + var e Int + e.Set(a.z) + if e.Cmp(&zero) < 0 { + e.Sub(&zero, &e) + } + if z.Cmp(&e) != 0 { + t.Errorf("got z = %v; want %v", z, e) + } + } +} + + func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) { var z Int f(&z, a.x, a.y) if !isNormalized(&z) { - t.Errorf("msg: %v is not normalized", z, msg) + t.Errorf("%s%v is not normalized", z, msg) } if (&z).Cmp(a.z) != 0 { t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z) @@ -157,28 +186,25 @@ func TestMul(t *testing.T) { } -type mulRangeZ struct { +var mulRangesZ = []struct { a, b int64 prod string -} - - -var mulRangesZ = []mulRangeZ{ +}{ // entirely positive ranges are covered by mulRangesN - mulRangeZ{-1, 1, "0"}, - mulRangeZ{-2, -1, "2"}, - mulRangeZ{-3, -2, "6"}, - mulRangeZ{-3, -1, "-6"}, - mulRangeZ{1, 3, "6"}, - mulRangeZ{-10, -10, "-10"}, - mulRangeZ{0, -1, "1"}, // empty range - mulRangeZ{-1, -100, "1"}, // empty range - mulRangeZ{-1, 1, "0"}, // range includes 0 - mulRangeZ{-1e9, 0, "0"}, // range includes 0 - mulRangeZ{-1e9, 1e9, "0"}, // range includes 0 - mulRangeZ{-10, -1, "3628800"}, // 10! - mulRangeZ{-20, -2, "-2432902008176640000"}, // -20! - mulRangeZ{-99, -1, + {-1, 1, "0"}, + {-2, -1, "2"}, + {-3, -2, "6"}, + {-3, -1, "-6"}, + {1, 3, "6"}, + {-10, -10, "-10"}, + {0, -1, "1"}, // empty range + {-1, -100, "1"}, // empty range + {-1, 1, "0"}, // range includes 0 + {-1e9, 0, "0"}, // range includes 0 + {-1e9, 1e9, "0"}, // range includes 0 + {-10, -1, "3628800"}, // 10! + {-20, -2, "-2432902008176640000"}, // -20! + {-99, -1, "-933262154439441526816992388562667004907159682643816214685929" + "638952175999932299156089414639761565182862536979208272237582" + "511852109168640000000000000000000000", // -99! @@ -205,50 +231,52 @@ func TestMulRangeZ(t *testing.T) { } -type stringTest struct { +var stringTests = []struct { in string out string base int val int64 ok bool -} - - -var stringTests = []stringTest{ - stringTest{in: "", ok: false}, - stringTest{in: "a", ok: false}, - stringTest{in: "z", ok: false}, - stringTest{in: "+", ok: false}, - stringTest{in: "0b", ok: false}, - stringTest{in: "0x", ok: false}, - stringTest{in: "2", base: 2, ok: false}, - stringTest{in: "0b2", base: 0, ok: false}, - stringTest{in: "08", ok: false}, - stringTest{in: "8", base: 8, ok: false}, - stringTest{in: "0xg", base: 0, ok: false}, - stringTest{in: "g", base: 16, ok: false}, - stringTest{"0", "0", 0, 0, true}, - stringTest{"0", "0", 10, 0, true}, - stringTest{"0", "0", 16, 0, true}, - stringTest{"10", "10", 0, 10, true}, - stringTest{"10", "10", 10, 10, true}, - stringTest{"10", "10", 16, 16, true}, - stringTest{"-10", "-10", 16, -16, true}, - stringTest{"0x10", "16", 0, 16, true}, - stringTest{in: "0x10", base: 16, ok: false}, - stringTest{"-0x10", "-16", 0, -16, true}, - stringTest{"00", "0", 0, 0, true}, - stringTest{"0", "0", 8, 0, true}, - stringTest{"07", "7", 0, 7, true}, - stringTest{"7", "7", 8, 7, true}, - stringTest{"023", "19", 0, 19, true}, - stringTest{"23", "23", 8, 19, true}, - stringTest{"cafebabe", "cafebabe", 16, 0xcafebabe, true}, - stringTest{"0b0", "0", 0, 0, true}, - stringTest{"-111", "-111", 2, -7, true}, - stringTest{"-0b111", "-7", 0, -7, true}, - stringTest{"0b1001010111", "599", 0, 0x257, true}, - stringTest{"1001010111", "1001010111", 2, 0x257, true}, +}{ + {in: "", ok: false}, + {in: "a", ok: false}, + {in: "z", ok: false}, + {in: "+", ok: false}, + {in: "-", ok: false}, + {in: "0b", ok: false}, + {in: "0x", ok: false}, + {in: "2", base: 2, ok: false}, + {in: "0b2", base: 0, ok: false}, + {in: "08", ok: false}, + {in: "8", base: 8, ok: false}, + {in: "0xg", base: 0, ok: false}, + {in: "g", base: 16, ok: false}, + {"0", "0", 0, 0, true}, + {"0", "0", 10, 0, true}, + {"0", "0", 16, 0, true}, + {"+0", "0", 0, 0, true}, + {"-0", "0", 0, 0, true}, + {"10", "10", 0, 10, true}, + {"10", "10", 10, 10, true}, + {"10", "10", 16, 16, true}, + {"-10", "-10", 16, -16, true}, + {"+10", "10", 16, 16, true}, + {"0x10", "16", 0, 16, true}, + {in: "0x10", base: 16, ok: false}, + {"-0x10", "-16", 0, -16, true}, + {"+0x10", "16", 0, 16, true}, + {"00", "0", 0, 0, true}, + {"0", "0", 8, 0, true}, + {"07", "7", 0, 7, true}, + {"7", "7", 8, 7, true}, + {"023", "19", 0, 19, true}, + {"23", "23", 8, 19, true}, + {"cafebabe", "cafebabe", 16, 0xcafebabe, true}, + {"0b0", "0", 0, 0, true}, + {"-111", "-111", 2, -7, true}, + {"-0b111", "-7", 0, -7, true}, + {"0b1001010111", "599", 0, 0x257, true}, + {"1001010111", "1001010111", 2, 0x257, true}, } @@ -276,13 +304,13 @@ func TestGetString(t *testing.T) { if test.base == 10 { s := z.String() if s != test.out { - t.Errorf("#%da got %s; want %s\n", i, s, test.out) + t.Errorf("#%da got %s; want %s", i, s, test.out) } } s := fmt.Sprintf(format(test.base), z) if s != test.out { - t.Errorf("#%db got %s; want %s\n", i, s, test.out) + t.Errorf("#%db got %s; want %s", i, s, test.out) } } } @@ -310,30 +338,27 @@ func TestSetString(t *testing.T) { } if n1.Cmp(expected) != 0 { - t.Errorf("#%d (input '%s') got: %s want: %d\n", i, test.in, n1, test.val) + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) } if n2.Cmp(expected) != 0 { - t.Errorf("#%d (input '%s') got: %s want: %d\n", i, test.in, n2, test.val) + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) } } } -type divisionSignsTest struct { +// Examples from the Go Language Spec, section "Arithmetic operators" +var divisionSignsTests = []struct { x, y int64 q, r int64 // T-division d, m int64 // Euclidian division -} - - -// Examples from the Go Language Spec, section "Arithmetic operators" -var divisionSignsTests = []divisionSignsTest{ - divisionSignsTest{5, 3, 1, 2, 1, 2}, - divisionSignsTest{-5, 3, -1, -2, -2, 1}, - divisionSignsTest{5, -3, -1, 2, -1, 2}, - divisionSignsTest{-5, -3, 1, -2, 2, 1}, - divisionSignsTest{1, 2, 0, 1, 0, 1}, - divisionSignsTest{8, 4, 2, 0, 2, 0}, +}{ + {5, 3, 1, 2, 1, 2}, + {-5, 3, -1, -2, -2, 1}, + {5, -3, -1, 2, -1, 2}, + {-5, -3, 1, -2, 2, 1}, + {1, 2, 0, 1, 0, 1}, + {8, 4, 2, 0, 2, 0}, } @@ -454,20 +479,17 @@ func checkQuo(x, y []byte) bool { } -type quoTest struct { +var quoTests = []struct { x, y string q, r string -} - - -var quoTests = []quoTest{ - quoTest{ +}{ + { "476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357", "9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996", "50911", "1", }, - quoTest{ + { "11510768301994997771168", "1328165573307167369775", "8", @@ -517,25 +539,22 @@ func TestQuoStepD6(t *testing.T) { } -type bitLenTest struct { +var bitLenTests = []struct { in string out int -} - - -var bitLenTests = []bitLenTest{ - bitLenTest{"-1", 1}, - bitLenTest{"0", 0}, - bitLenTest{"1", 1}, - bitLenTest{"2", 2}, - bitLenTest{"4", 3}, - bitLenTest{"0xabc", 12}, - bitLenTest{"0x8000", 16}, - bitLenTest{"0x80000000", 32}, - bitLenTest{"0x800000000000", 48}, - bitLenTest{"0x8000000000000000", 64}, - bitLenTest{"0x80000000000000000000", 80}, - bitLenTest{"-0x4000000000000000000000", 87}, +}{ + {"-1", 1}, + {"0", 0}, + {"1", 1}, + {"2", 2}, + {"4", 3}, + {"0xabc", 12}, + {"0x8000", 16}, + {"0x80000000", 32}, + {"0x800000000000", 48}, + {"0x8000000000000000", 64}, + {"0x80000000000000000000", 80}, + {"-0x4000000000000000000000", 87}, } @@ -548,32 +567,29 @@ func TestBitLen(t *testing.T) { } if n := x.BitLen(); n != test.out { - t.Errorf("#%d got %d want %d\n", i, n, test.out) + t.Errorf("#%d got %d want %d", i, n, test.out) } } } -type expTest struct { +var expTests = []struct { x, y, m string out string -} - - -var expTests = []expTest{ - expTest{"5", "0", "", "1"}, - expTest{"-5", "0", "", "-1"}, - expTest{"5", "1", "", "5"}, - expTest{"-5", "1", "", "-5"}, - expTest{"-2", "3", "2", "0"}, - expTest{"5", "2", "", "25"}, - expTest{"1", "65537", "2", "1"}, - expTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, - expTest{"0x8000000000000000", "2", "6719", "4944"}, - expTest{"0x8000000000000000", "3", "6719", "5447"}, - expTest{"0x8000000000000000", "1000", "6719", "1603"}, - expTest{"0x8000000000000000", "1000000", "6719", "3199"}, - expTest{ +}{ + {"5", "0", "", "1"}, + {"-5", "0", "", "-1"}, + {"5", "1", "", "5"}, + {"-5", "1", "", "-5"}, + {"-2", "3", "2", "0"}, + {"5", "2", "", "25"}, + {"1", "65537", "2", "1"}, + {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, + {"0x8000000000000000", "2", "6719", "4944"}, + {"0x8000000000000000", "3", "6719", "5447"}, + {"0x8000000000000000", "1000", "6719", "1603"}, + {"0x8000000000000000", "1000000", "6719", "3199"}, + { "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347", "298472983472983471903246121093472394872319615612417471234712061", "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464", @@ -630,14 +646,11 @@ func checkGcd(aBytes, bBytes []byte) bool { } -type gcdTest struct { +var gcdTests = []struct { a, b int64 d, x, y int64 -} - - -var gcdTests = []gcdTest{ - gcdTest{120, 23, 1, -9, 47}, +}{ + {120, 23, 1, -9, 47}, } @@ -726,30 +739,30 @@ type intShiftTest struct { var rshTests = []intShiftTest{ - intShiftTest{"0", 0, "0"}, - intShiftTest{"-0", 0, "0"}, - intShiftTest{"0", 1, "0"}, - intShiftTest{"0", 2, "0"}, - intShiftTest{"1", 0, "1"}, - intShiftTest{"1", 1, "0"}, - intShiftTest{"1", 2, "0"}, - intShiftTest{"2", 0, "2"}, - intShiftTest{"2", 1, "1"}, - intShiftTest{"-1", 0, "-1"}, - intShiftTest{"-1", 1, "-1"}, - intShiftTest{"-1", 10, "-1"}, - intShiftTest{"-100", 2, "-25"}, - intShiftTest{"-100", 3, "-13"}, - intShiftTest{"-100", 100, "-1"}, - intShiftTest{"4294967296", 0, "4294967296"}, - intShiftTest{"4294967296", 1, "2147483648"}, - intShiftTest{"4294967296", 2, "1073741824"}, - intShiftTest{"18446744073709551616", 0, "18446744073709551616"}, - intShiftTest{"18446744073709551616", 1, "9223372036854775808"}, - intShiftTest{"18446744073709551616", 2, "4611686018427387904"}, - intShiftTest{"18446744073709551616", 64, "1"}, - intShiftTest{"340282366920938463463374607431768211456", 64, "18446744073709551616"}, - intShiftTest{"340282366920938463463374607431768211456", 128, "1"}, + {"0", 0, "0"}, + {"-0", 0, "0"}, + {"0", 1, "0"}, + {"0", 2, "0"}, + {"1", 0, "1"}, + {"1", 1, "0"}, + {"1", 2, "0"}, + {"2", 0, "2"}, + {"2", 1, "1"}, + {"-1", 0, "-1"}, + {"-1", 1, "-1"}, + {"-1", 10, "-1"}, + {"-100", 2, "-25"}, + {"-100", 3, "-13"}, + {"-100", 100, "-1"}, + {"4294967296", 0, "4294967296"}, + {"4294967296", 1, "2147483648"}, + {"4294967296", 2, "1073741824"}, + {"18446744073709551616", 0, "18446744073709551616"}, + {"18446744073709551616", 1, "9223372036854775808"}, + {"18446744073709551616", 2, "4611686018427387904"}, + {"18446744073709551616", 64, "1"}, + {"340282366920938463463374607431768211456", 64, "18446744073709551616"}, + {"340282366920938463463374607431768211456", 128, "1"}, } @@ -786,25 +799,25 @@ func TestRshSelf(t *testing.T) { var lshTests = []intShiftTest{ - intShiftTest{"0", 0, "0"}, - intShiftTest{"0", 1, "0"}, - intShiftTest{"0", 2, "0"}, - intShiftTest{"1", 0, "1"}, - intShiftTest{"1", 1, "2"}, - intShiftTest{"1", 2, "4"}, - intShiftTest{"2", 0, "2"}, - intShiftTest{"2", 1, "4"}, - intShiftTest{"2", 2, "8"}, - intShiftTest{"-87", 1, "-174"}, - intShiftTest{"4294967296", 0, "4294967296"}, - intShiftTest{"4294967296", 1, "8589934592"}, - intShiftTest{"4294967296", 2, "17179869184"}, - intShiftTest{"18446744073709551616", 0, "18446744073709551616"}, - intShiftTest{"9223372036854775808", 1, "18446744073709551616"}, - intShiftTest{"4611686018427387904", 2, "18446744073709551616"}, - intShiftTest{"1", 64, "18446744073709551616"}, - intShiftTest{"18446744073709551616", 64, "340282366920938463463374607431768211456"}, - intShiftTest{"1", 128, "340282366920938463463374607431768211456"}, + {"0", 0, "0"}, + {"0", 1, "0"}, + {"0", 2, "0"}, + {"1", 0, "1"}, + {"1", 1, "2"}, + {"1", 2, "4"}, + {"2", 0, "2"}, + {"2", 1, "4"}, + {"2", 2, "8"}, + {"-87", 1, "-174"}, + {"4294967296", 0, "4294967296"}, + {"4294967296", 1, "8589934592"}, + {"4294967296", 2, "17179869184"}, + {"18446744073709551616", 0, "18446744073709551616"}, + {"9223372036854775808", 1, "18446744073709551616"}, + {"4611686018427387904", 2, "18446744073709551616"}, + {"1", 64, "18446744073709551616"}, + {"18446744073709551616", 64, "340282366920938463463374607431768211456"}, + {"1", 128, "340282366920938463463374607431768211456"}, } @@ -894,26 +907,24 @@ func TestInt64(t *testing.T) { } -type bitwiseTest struct { +var bitwiseTests = []struct { x, y string and, or, xor, andNot string -} - -var bitwiseTests = []bitwiseTest{ - bitwiseTest{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"}, - bitwiseTest{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"}, - bitwiseTest{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"}, - bitwiseTest{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"}, - bitwiseTest{"-0xAF", "-0x50", "0x00", "-0xFF", "-0x01", "-0x01"}, - bitwiseTest{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"}, - bitwiseTest{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"}, - bitwiseTest{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"}, - bitwiseTest{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"}, - bitwiseTest{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"}, - bitwiseTest{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"}, - bitwiseTest{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"}, - bitwiseTest{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"}, - bitwiseTest{ +}{ + {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"}, + {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"}, + {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"}, + {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"}, + {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"}, + {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"}, + {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"}, + {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"}, + {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"}, + {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"}, + {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"}, + {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"}, + {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"}, + { "0x1000009dc6e3d9822cba04129bcbe3401", "0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd", "0x1000001186210100001000009048c2001", @@ -921,7 +932,7 @@ var bitwiseTests = []bitwiseTest{ "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc", "0x8c40c2d8822caa04120b8321400", }, - bitwiseTest{ + { "0x1000009dc6e3d9822cba04129bcbe3401", "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd", "0x8c40c2d8822caa04120b8321401", @@ -929,7 +940,7 @@ var bitwiseTests = []bitwiseTest{ "-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe", "0x1000001186210100001000009048c2000", }, - bitwiseTest{ + { "-0x1000009dc6e3d9822cba04129bcbe3401", "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd", "-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd", @@ -944,24 +955,24 @@ type bitFun func(z, x, y *Int) *Int func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { expected := new(Int) - expected.SetString(exp, 16) + expected.SetString(exp, 0) out := f(new(Int), x, y) if out.Cmp(expected) != 0 { - println("Test failed") t.Errorf("%s: got %s want %s", msg, out, expected) } } func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { + self := new(Int) + self.Set(x) expected := new(Int) - expected.SetString(exp, 16) + expected.SetString(exp, 0) - x = f(x, x, y) - if x.Cmp(expected) != 0 { - println("Test failed") - t.Errorf("%s: got %s want %s", msg, x, expected) + self = f(self, self, y) + if self.Cmp(expected) != 0 { + t.Errorf("%s: got %s want %s", msg, self, expected) } } @@ -970,8 +981,8 @@ func TestBitwise(t *testing.T) { x := new(Int) y := new(Int) for _, test := range bitwiseTests { - x.SetString(test.x, 16) - y.SetString(test.y, 16) + x.SetString(test.x, 0) + y.SetString(test.y, 0) testBitFun(t, "and", (*Int).And, x, y, test.and) testBitFunSelf(t, "and", (*Int).And, x, y, test.and) @@ -985,18 +996,16 @@ func TestBitwise(t *testing.T) { } -type notTest struct { +var notTests = []struct { in string out string -} - -var notTests = []notTest{ - notTest{"0", "-1"}, - notTest{"1", "-2"}, - notTest{"7", "-8"}, - notTest{"0", "-1"}, - notTest{"-81910", "81909"}, - notTest{ +}{ + {"0", "-1"}, + {"1", "-2"}, + {"7", "-8"}, + {"0", "-1"}, + {"-81910", "81909"}, + { "298472983472983471903246121093472394872319615612417471234712061", "-298472983472983471903246121093472394872319615612417471234712062", }, @@ -1021,15 +1030,13 @@ func TestNot(t *testing.T) { } -type modInverseTest struct { +var modInverseTests = []struct { element string prime string -} - -var modInverseTests = []modInverseTest{ - modInverseTest{"1", "7"}, - modInverseTest{"1", "13"}, - modInverseTest{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"}, +}{ + {"1", "7"}, + {"1", "13"}, + {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"}, } func TestModInverse(t *testing.T) { diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go index dc2e6be28..a308f69e8 100755 --- a/src/pkg/big/nat.go +++ b/src/pkg/big/nat.go @@ -103,9 +103,7 @@ func (z nat) setUint64(x uint64) nat { func (z nat) set(x nat) nat { z = z.make(len(x)) - for i, d := range x { - z[i] = d - } + copy(z, x) return z } @@ -666,7 +664,7 @@ func (z nat) scan(s string, base int) (nat, int, int) { } } - return z, base, i + return z.norm(), base, i } @@ -818,13 +816,13 @@ func (z nat) or(x, y nat) nat { n, m = m, n s = y } - // n >= m + // m >= n - z = z.make(n) - for i := 0; i < m; i++ { + z = z.make(m) + for i := 0; i < n; i++ { z[i] = x[i] | y[i] } - copy(z[m:n], s[m:n]) + copy(z[n:m], s[n:m]) return z.norm() } @@ -834,17 +832,17 @@ func (z nat) xor(x, y nat) nat { m := len(x) n := len(y) s := x - if n < m { + if m < n { n, m = m, n s = y } - // n >= m + // m >= n - z = z.make(n) - for i := 0; i < m; i++ { + z = z.make(m) + for i := 0; i < n; i++ { z[i] = x[i] ^ y[i] } - copy(z[m:n], s[m:n]) + copy(z[n:m], s[n:m]) return z.norm() } diff --git a/src/pkg/big/nat_test.go b/src/pkg/big/nat_test.go index 8545981c0..0bcb94554 100755 --- a/src/pkg/big/nat_test.go +++ b/src/pkg/big/nat_test.go @@ -6,27 +6,24 @@ package big import "testing" -type cmpTest struct { +var cmpTests = []struct { x, y nat r int -} - - -var cmpTests = []cmpTest{ - cmpTest{nil, nil, 0}, - cmpTest{nil, nat{}, 0}, - cmpTest{nat{}, nil, 0}, - cmpTest{nat{}, nat{}, 0}, - cmpTest{nat{0}, nat{0}, 0}, - cmpTest{nat{0}, nat{1}, -1}, - cmpTest{nat{1}, nat{0}, 1}, - cmpTest{nat{1}, nat{1}, 0}, - cmpTest{nat{0, _M}, nat{1}, 1}, - cmpTest{nat{1}, nat{0, _M}, -1}, - cmpTest{nat{1, _M}, nat{0, _M}, 1}, - cmpTest{nat{0, _M}, nat{1, _M}, -1}, - cmpTest{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1}, - cmpTest{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1}, +}{ + {nil, nil, 0}, + {nil, nat{}, 0}, + {nat{}, nil, 0}, + {nat{}, nat{}, 0}, + {nat{0}, nat{0}, 0}, + {nat{0}, nat{1}, -1}, + {nat{1}, nat{0}, 1}, + {nat{1}, nat{1}, 0}, + {nat{0, _M}, nat{1}, 1}, + {nat{1}, nat{0, _M}, -1}, + {nat{1, _M}, nat{0, _M}, 1}, + {nat{0, _M}, nat{1, _M}, -1}, + {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1}, + {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1}, } @@ -47,24 +44,24 @@ type argNN struct { var sumNN = []argNN{ - argNN{}, - argNN{nat{1}, nil, nat{1}}, - argNN{nat{1111111110}, nat{123456789}, nat{987654321}}, - argNN{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}}, - argNN{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}}, - argNN{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}}, + {}, + {nat{1}, nil, nat{1}}, + {nat{1111111110}, nat{123456789}, nat{987654321}}, + {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}}, + {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}}, + {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}}, } var prodNN = []argNN{ - argNN{}, - argNN{nil, nil, nil}, - argNN{nil, nat{991}, nil}, - argNN{nat{991}, nat{991}, nat{1}}, - argNN{nat{991 * 991}, nat{991}, nat{991}}, - argNN{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}}, - argNN{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}}, - argNN{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}}, + {}, + {nil, nil, nil}, + {nil, nat{991}, nil}, + {nat{991}, nat{991}, nat{1}}, + {nat{991 * 991}, nat{991}, nat{991}}, + {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}}, + {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}}, + {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}}, } @@ -111,25 +108,22 @@ func TestFunNN(t *testing.T) { } -type mulRangeN struct { +var mulRangesN = []struct { a, b uint64 prod string -} - - -var mulRangesN = []mulRangeN{ - mulRangeN{0, 0, "0"}, - mulRangeN{1, 1, "1"}, - mulRangeN{1, 2, "2"}, - mulRangeN{1, 3, "6"}, - mulRangeN{10, 10, "10"}, - mulRangeN{0, 100, "0"}, - mulRangeN{0, 1e9, "0"}, - mulRangeN{1, 0, "1"}, // empty range - mulRangeN{100, 1, "1"}, // empty range - mulRangeN{1, 10, "3628800"}, // 10! - mulRangeN{1, 20, "2432902008176640000"}, // 20! - mulRangeN{1, 100, +}{ + {0, 0, "0"}, + {1, 1, "1"}, + {1, 2, "2"}, + {1, 3, "6"}, + {10, 10, "10"}, + {0, 100, "0"}, + {0, 1e9, "0"}, + {1, 0, "1"}, // empty range + {100, 1, "1"}, // empty range + {1, 10, "3628800"}, // 10! + {1, 20, "2432902008176640000"}, // 20! + {1, 100, "933262154439441526816992388562667004907159682643816214685929" + "638952175999932299156089414639761565182862536979208272237582" + "51185210916864000000000000000000000000", // 100! @@ -173,18 +167,15 @@ func BenchmarkMul(b *testing.B) { } -type str struct { +var tab = []struct { x nat b int s string -} - - -var tab = []str{ - str{nil, 10, "0"}, - str{nat{1}, 10, "1"}, - str{nat{10}, 10, "10"}, - str{nat{1234567890}, 10, "1234567890"}, +}{ + {nil, 10, "0"}, + {nat{1}, 10, "1"}, + {nat{10}, 10, "10"}, + {nat{1234567890}, 10, "1234567890"}, } @@ -228,12 +219,12 @@ type shiftTest struct { var leftShiftTests = []shiftTest{ - shiftTest{nil, 0, nil}, - shiftTest{nil, 1, nil}, - shiftTest{natOne, 0, natOne}, - shiftTest{natOne, 1, natTwo}, - shiftTest{nat{1 << (_W - 1)}, 1, nat{0}}, - shiftTest{nat{1 << (_W - 1), 0}, 1, nat{0, 1}}, + {nil, 0, nil}, + {nil, 1, nil}, + {natOne, 0, natOne}, + {natOne, 1, natTwo}, + {nat{1 << (_W - 1)}, 1, nat{0}}, + {nat{1 << (_W - 1), 0}, 1, nat{0, 1}}, } @@ -252,13 +243,13 @@ func TestShiftLeft(t *testing.T) { var rightShiftTests = []shiftTest{ - shiftTest{nil, 0, nil}, - shiftTest{nil, 1, nil}, - shiftTest{natOne, 0, natOne}, - shiftTest{natOne, 1, nil}, - shiftTest{natTwo, 1, natOne}, - shiftTest{nat{0, 1}, 1, nat{1 << (_W - 1)}}, - shiftTest{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}}, + {nil, 0, nil}, + {nil, 1, nil}, + {natOne, 0, natOne}, + {natOne, 1, nil}, + {natTwo, 1, natOne}, + {nat{0, 1}, 1, nat{1 << (_W - 1)}}, + {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}}, } @@ -284,12 +275,12 @@ type modWTest struct { var modWTests32 = []modWTest{ - modWTest{"23492635982634928349238759823742", "252341", "220170"}, + {"23492635982634928349238759823742", "252341", "220170"}, } var modWTests64 = []modWTest{ - modWTest{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"}, + {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"}, } @@ -301,7 +292,7 @@ func runModWTests(t *testing.T, tests []modWTest) { r := in.abs.modW(d.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", i, r, out) } } } @@ -322,26 +313,23 @@ func TestTrailingZeroBits(t *testing.T) { x-- for i := 0; i < _W; i++ { if trailingZeroBits(x) != i { - t.Errorf("Failed at step %d: x: %x got: %d\n", i, x, trailingZeroBits(x)) + t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x)) } x <<= 1 } } -type expNNTest struct { +var expNNTests = []struct { x, y, m string out string -} - - -var expNNTests = []expNNTest{ - expNNTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, - expNNTest{"0x8000000000000000", "2", "6719", "4944"}, - expNNTest{"0x8000000000000000", "3", "6719", "5447"}, - expNNTest{"0x8000000000000000", "1000", "6719", "1603"}, - expNNTest{"0x8000000000000000", "1000000", "6719", "3199"}, - expNNTest{ +}{ + {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, + {"0x8000000000000000", "2", "6719", "4944"}, + {"0x8000000000000000", "3", "6719", "5447"}, + {"0x8000000000000000", "1000", "6719", "1603"}, + {"0x8000000000000000", "1000000", "6719", "3199"}, + { "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347", "298472983472983471903246121093472394872319615612417471234712061", "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464", diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go index ddd858d5c..e70673a1c 100644 --- a/src/pkg/big/rat.go +++ b/src/pkg/big/rat.go @@ -35,9 +35,8 @@ func (z *Rat) SetFrac(a, b *Int) *Rat { func (z *Rat) SetFrac64(a, b int64) *Rat { z.a.SetInt64(a) if b < 0 { - z.b.setUint64(uint64(-b)) + b = -b z.a.neg = !z.a.neg - return z.norm() } z.b = z.b.setUint64(uint64(b)) return z.norm() @@ -60,6 +59,23 @@ func (z *Rat) SetInt64(x int64) *Rat { } +// Sign returns: +// +// -1 if x < 0 +// 0 if x == 0 +// +1 if x > 0 +// +func (x *Rat) Sign() int { + return x.a.Sign() +} + + +// IsInt returns true if the denominator of x is 1. +func (x *Rat) IsInt() bool { + return len(x.b) == 1 && x.b[0] == 1 +} + + // Num returns the numerator of z; it may be <= 0. // The result is a reference to z's numerator; it // may change if a new value is assigned to z. @@ -126,6 +142,14 @@ func (x *Rat) Cmp(y *Rat) (r int) { } +// Abs sets z to |x| (the absolute value of x) and returns z. +func (z *Rat) Abs(x *Rat) *Rat { + z.a.Abs(&x.a) + z.b = z.b.set(x.b) + return z +} + + // Add sets z to the sum x+y and returns z. func (z *Rat) Add(x, y *Rat) *Rat { a1 := mulNat(&x.a, y.b) @@ -186,26 +210,17 @@ func (z *Rat) Set(x *Rat) *Rat { // SetString sets z to the value of s and returns z and a boolean indicating -// success. s can be given as a fraction "a/b" or as a decimal number "a.b". -// If the operation failed, the value of z is undefined. +// success. s can be given as a fraction "a/b" or as a floating-point number +// optionally followed by an exponent. If the operation failed, the value of z +// is undefined. func (z *Rat) SetString(s string) (*Rat, bool) { if len(s) == 0 { return z, false } - // Check for a decimal point - sep := strings.Index(s, ".") - if sep < 0 { - // Check for a quotient - sep = strings.Index(s, "/") - if sep < 0 { - // Just read in the string as an integer - if _, ok := z.a.SetString(s, 10); !ok { - return z, false - } - z.b = z.b.setWord(1) - return z, true - } + // check for a quotient + sep := strings.Index(s, "/") + if sep >= 0 { if _, ok := z.a.SetString(s[0:sep], 10); !ok { return z, false } @@ -214,59 +229,98 @@ func (z *Rat) SetString(s string) (*Rat, bool) { if z.b, _, n = z.b.scan(s, 10); n != len(s) { return z, false } - return z.norm(), true } - s = s[0:sep] + s[sep+1:] + // check for a decimal point + sep = strings.Index(s, ".") + // check for an exponent + e := strings.IndexAny(s, "eE") + var exp Int + if e >= 0 { + if e < sep { + // The E must come after the decimal point. + return z, false + } + if _, ok := exp.SetString(s[e+1:], 10); !ok { + return z, false + } + s = s[0:e] + } + if sep >= 0 { + s = s[0:sep] + s[sep+1:] + exp.Sub(&exp, NewInt(int64(len(s)-sep))) + } + if _, ok := z.a.SetString(s, 10); !ok { return z, false } - z.b = z.b.expNN(natTen, nat{Word(len(s) - sep)}, nil) + powTen := nat{}.expNN(natTen, exp.abs, nil) + if exp.neg { + z.b = powTen + z.norm() + } else { + z.a.abs = z.a.abs.mul(z.a.abs, powTen) + z.b = z.b.setWord(1) + } - return z.norm(), true + return z, true } -// String returns a string representation of z in the form "a/b". +// String returns a string representation of z in the form "a/b" (even if b == 1). func (z *Rat) String() string { - s := z.a.String() - if len(z.b) == 1 && z.b[0] == 1 { - return s + return z.a.String() + "/" + z.b.string(10) +} + + +// RatString returns a string representation of z in the form "a/b" if b != 1, +// and in the form "a" if b == 1. +func (z *Rat) RatString() string { + if z.IsInt() { + return z.a.String() } - return s + "/" + z.b.string(10) + return z.String() } // FloatString returns a string representation of z in decimal form with prec // digits of precision after the decimal point and the last digit rounded. func (z *Rat) FloatString(prec int) string { - q, r := nat{}.div(nat{}, z.a.abs, z.b) - - s := "" - if z.a.neg { - s = "-" + if z.IsInt() { + return z.a.String() } - s += q.string(10) - if len(z.b) == 1 && z.b[0] == 1 { - return s + q, r := nat{}.div(nat{}, z.a.abs, z.b) + + p := natOne + if prec > 0 { + p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil) } - p := nat{}.expNN(natTen, nat{Word(prec)}, nil) r = r.mul(r, p) r, r2 := r.div(nat{}, r, z.b) - // See if we need to round up - r2 = r2.mul(r2, natTwo) + // see if we need to round up + r2 = r2.add(r2, r2) if z.b.cmp(r2) <= 0 { r = r.add(r, natOne) + if r.cmp(p) >= 0 { + q = nat{}.add(q, natOne) + r = nat{}.sub(r, p) + } } - rs := r.string(10) - leadingZeros := prec - len(rs) - s += "." + strings.Repeat("0", leadingZeros) + rs - s = strings.TrimRight(s, "0") + s := q.string(10) + if z.a.neg { + s = "-" + s + } + + if prec > 0 { + rs := r.string(10) + leadingZeros := prec - len(rs) + s += "." + strings.Repeat("0", leadingZeros) + rs + } return s } diff --git a/src/pkg/big/rat_test.go b/src/pkg/big/rat_test.go index 2379cc0d5..8f42949b0 100644 --- a/src/pkg/big/rat_test.go +++ b/src/pkg/big/rat_test.go @@ -7,57 +7,71 @@ package big import "testing" -type setStringTest struct { +var setStringTests = []struct { in, out string ok bool -} - -var setStringTests = []setStringTest{ - setStringTest{"0", "0", true}, - setStringTest{"-0", "0", true}, - setStringTest{"1", "1", true}, - setStringTest{"-1", "-1", true}, - setStringTest{in: "r", ok: false}, - setStringTest{in: "a/b", ok: false}, - setStringTest{in: "a.b", ok: false}, - setStringTest{"-0.1", "-1/10", true}, - setStringTest{"-.1", "-1/10", true}, - setStringTest{"2/4", "1/2", true}, - setStringTest{".25", "1/4", true}, - setStringTest{"-1/5", "-1/5", true}, - setStringTest{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true}, - setStringTest{"53/70893980658822810696", "53/70893980658822810696", true}, - setStringTest{"106/141787961317645621392", "53/70893980658822810696", true}, - setStringTest{"204211327800791583.81095", "4084226556015831676219/20000", true}, +}{ + {"0", "0", true}, + {"-0", "0", true}, + {"1", "1", true}, + {"-1", "-1", true}, + {"1.", "1", true}, + {"1e0", "1", true}, + {"1.e1", "10", true}, + {in: "1e", ok: false}, + {in: "1.e", ok: false}, + {in: "1e+14e-5", ok: false}, + {in: "1e4.5", ok: false}, + {in: "r", ok: false}, + {in: "a/b", ok: false}, + {in: "a.b", ok: false}, + {"-0.1", "-1/10", true}, + {"-.1", "-1/10", true}, + {"2/4", "1/2", true}, + {".25", "1/4", true}, + {"-1/5", "-1/5", true}, + {"8129567.7690E14", "812956776900000000000", true}, + {"78189e+4", "781890000", true}, + {"553019.8935e+8", "55301989350000", true}, + {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true}, + {"9877861857500000E-7", "3951144743/4", true}, + {"2169378.417e-3", "2169378417/1000000", true}, + {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true}, + {"53/70893980658822810696", "53/70893980658822810696", true}, + {"106/141787961317645621392", "53/70893980658822810696", true}, + {"204211327800791583.81095", "4084226556015831676219/20000", true}, } func TestRatSetString(t *testing.T) { for i, test := range setStringTests { x, ok := new(Rat).SetString(test.in) - if ok != test.ok || ok && x.String() != test.out { - t.Errorf("#%d got %s want %s", i, x.String(), test.out) + if ok != test.ok || ok && x.RatString() != test.out { + t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) } } } -type floatStringTest struct { +var floatStringTests = []struct { in string prec int out string -} - -var floatStringTests = []floatStringTest{ - floatStringTest{"0", 0, "0"}, - floatStringTest{"0", 4, "0"}, - floatStringTest{"1", 0, "1"}, - floatStringTest{"1", 2, "1"}, - floatStringTest{"-1", 0, "-1"}, - floatStringTest{".25", 2, "0.25"}, - floatStringTest{".25", 1, "0.3"}, - floatStringTest{"-1/3", 3, "-0.333"}, - floatStringTest{"-2/3", 4, "-0.6667"}, +}{ + {"0", 0, "0"}, + {"0", 4, "0"}, + {"1", 0, "1"}, + {"1", 2, "1"}, + {"-1", 0, "-1"}, + {".25", 2, "0.25"}, + {".25", 1, "0.3"}, + {"-1/3", 3, "-0.333"}, + {"-2/3", 4, "-0.6667"}, + {"0.96", 1, "1.0"}, + {"0.999", 2, "1.00"}, + {"0.9", 0, "1"}, + {".25", -1, "0"}, + {".55", -1, "1"}, } func TestFloatString(t *testing.T) { @@ -71,21 +85,33 @@ func TestFloatString(t *testing.T) { } -type ratCmpTest struct { - rat1, rat2 string - out int +func TestRatSign(t *testing.T) { + zero := NewRat(0, 1) + for _, a := range setStringTests { + var x Rat + x.SetString(a.in) + s := x.Sign() + e := x.Cmp(zero) + if s != e { + t.Errorf("got %d; want %d for z = %v", s, e, &x) + } + } } -var ratCmpTests = []ratCmpTest{ - ratCmpTest{"0", "0/1", 0}, - ratCmpTest{"1/1", "1", 0}, - ratCmpTest{"-1", "-2/2", 0}, - ratCmpTest{"1", "0", 1}, - ratCmpTest{"0/1", "1/1", -1}, - ratCmpTest{"-5/1434770811533343057144", "-5/1434770811533343057145", -1}, - ratCmpTest{"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1}, - ratCmpTest{"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1}, - ratCmpTest{"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0}, + +var ratCmpTests = []struct { + rat1, rat2 string + out int +}{ + {"0", "0/1", 0}, + {"1/1", "1", 0}, + {"-1", "-2/2", 0}, + {"1", "0", 1}, + {"0/1", "1/1", -1}, + {"-5/1434770811533343057144", "-5/1434770811533343057145", -1}, + {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1}, + {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1}, + {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0}, } func TestRatCmp(t *testing.T) { @@ -101,6 +127,38 @@ func TestRatCmp(t *testing.T) { } +func TestIsInt(t *testing.T) { + one := NewInt(1) + for _, a := range setStringTests { + var x Rat + x.SetString(a.in) + i := x.IsInt() + e := x.Denom().Cmp(one) == 0 + if i != e { + t.Errorf("got %v; want %v for z = %v", i, e, &x) + } + } +} + + +func TestRatAbs(t *testing.T) { + zero := NewRat(0, 1) + for _, a := range setStringTests { + var z Rat + z.SetString(a.in) + var e Rat + e.Set(&z) + if e.Cmp(zero) < 0 { + e.Sub(zero, &e) + } + z.Abs(&z) + if z.Cmp(&e) != 0 { + t.Errorf("got z = %v; want %v", &z, &e) + } + } +} + + type ratBinFun func(z, x, y *Rat) *Rat type ratBinArg struct { x, y, z string @@ -118,30 +176,28 @@ func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) { } -type ratBinTest struct { +var ratBinTests = []struct { x, y string sum, prod string -} - -var ratBinTests = []ratBinTest{ - ratBinTest{"0", "0", "0", "0"}, - ratBinTest{"0", "1", "1", "0"}, - ratBinTest{"-1", "0", "-1", "0"}, - ratBinTest{"-1", "1", "0", "-1"}, - ratBinTest{"1", "1", "2", "1"}, - ratBinTest{"1/2", "1/2", "1", "1/4"}, - ratBinTest{"1/4", "1/3", "7/12", "1/12"}, - ratBinTest{"2/5", "-14/3", "-64/15", "-28/15"}, - ratBinTest{"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"}, - ratBinTest{"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"}, - ratBinTest{"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"}, - ratBinTest{"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"}, - ratBinTest{"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"}, - ratBinTest{"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"}, - ratBinTest{"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"}, - ratBinTest{"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"}, - ratBinTest{"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"}, - ratBinTest{"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"}, +}{ + {"0", "0", "0", "0"}, + {"0", "1", "1", "0"}, + {"-1", "0", "-1", "0"}, + {"-1", "1", "0", "-1"}, + {"1", "1", "2", "1"}, + {"1/2", "1/2", "1", "1/4"}, + {"1/4", "1/3", "7/12", "1/12"}, + {"2/5", "-14/3", "-64/15", "-28/15"}, + {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"}, + {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"}, + {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"}, + {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"}, + {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"}, + {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"}, + {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"}, + {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"}, + {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"}, + {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"}, } func TestRatBin(t *testing.T) { @@ -201,3 +257,26 @@ func TestIssue820(t *testing.T) { t.Errorf("got %s want %s", z, q) } } + + +var setFrac64Tests = []struct { + a, b int64 + out string +}{ + {0, 1, "0"}, + {0, -1, "0"}, + {1, 1, "1"}, + {-1, 1, "-1"}, + {1, -1, "-1"}, + {-1, -1, "1"}, + {-9223372036854775808, -9223372036854775808, "1"}, +} + +func TestRatSetFrac64Rat(t *testing.T) { + for i, test := range setFrac64Tests { + x := new(Rat).SetFrac64(test.a, test.b) + if x.RatString() != test.out { + t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) + } + } +} |