diff options
Diffstat (limited to 'libgo/go/big/nat.go')
-rw-r--r-- | libgo/go/big/nat.go | 388 |
1 files changed, 273 insertions, 115 deletions
diff --git a/libgo/go/big/nat.go b/libgo/go/big/nat.go index 4848d42..be3aff2 100644 --- a/libgo/go/big/nat.go +++ b/libgo/go/big/nat.go @@ -18,7 +18,11 @@ package big // These are the building blocks for the operations on signed integers // and rationals. -import "rand" +import ( + "io" + "os" + "rand" +) // An unsigned integer x of the form // @@ -40,14 +44,12 @@ var ( natTen = nat{10} ) - func (z nat) clear() { for i := range z { z[i] = 0 } } - func (z nat) norm() nat { i := len(z) for i > 0 && z[i-1] == 0 { @@ -56,7 +58,6 @@ func (z nat) norm() nat { return z[0:i] } - func (z nat) make(n int) nat { if n <= cap(z) { return z[0:n] // reuse z @@ -67,7 +68,6 @@ func (z nat) make(n int) nat { return make(nat, n, n+e) } - func (z nat) setWord(x Word) nat { if x == 0 { return z.make(0) @@ -77,7 +77,6 @@ func (z nat) setWord(x Word) nat { return z } - func (z nat) setUint64(x uint64) nat { // single-digit values if w := Word(x); uint64(w) == x { @@ -100,14 +99,12 @@ func (z nat) setUint64(x uint64) nat { return z } - func (z nat) set(x nat) nat { z = z.make(len(x)) copy(z, x) return z } - func (z nat) add(x, y nat) nat { m := len(x) n := len(y) @@ -134,7 +131,6 @@ func (z nat) add(x, y nat) nat { return z.norm() } - func (z nat) sub(x, y nat) nat { m := len(x) n := len(y) @@ -163,7 +159,6 @@ func (z nat) sub(x, y nat) nat { return z.norm() } - func (x nat) cmp(y nat) (r int) { m := len(x) n := len(y) @@ -191,7 +186,6 @@ func (x nat) cmp(y nat) (r int) { return } - func (z nat) mulAddWW(x nat, y, r Word) nat { m := len(x) if m == 0 || y == 0 { @@ -205,7 +199,6 @@ func (z nat) mulAddWW(x nat, y, r Word) nat { return z.norm() } - // basicMul multiplies x and y and leaves the result in z. // The (non-normalized) result is placed in z[0 : len(x) + len(y)]. func basicMul(z, x, y nat) { @@ -217,7 +210,6 @@ func basicMul(z, x, y nat) { } } - // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. // Factored out for readability - do not use outside karatsuba. func karatsubaAdd(z, x nat, n int) { @@ -226,7 +218,6 @@ func karatsubaAdd(z, x nat, n int) { } } - // Like karatsubaAdd, but does subtract. func karatsubaSub(z, x nat, n int) { if c := subVV(z[0:n], z, x); c != 0 { @@ -234,7 +225,6 @@ func karatsubaSub(z, x nat, n int) { } } - // Operands that are shorter than karatsubaThreshold are multiplied using // "grade school" multiplication; for longer operands the Karatsuba algorithm // is used. @@ -339,13 +329,11 @@ func karatsuba(z, x, y nat) { } } - // alias returns true if x and y share the same base array. func alias(x, y nat) bool { return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1] } - // addAt implements z += x*(1<<(_W*i)); z must be long enough. // (we don't use nat.add because we need z to stay the same // slice, and we don't need to normalize z after each addition) @@ -360,7 +348,6 @@ func addAt(z, x nat, i int) { } } - func max(x, y int) int { if x > y { return x @@ -368,7 +355,6 @@ func max(x, y int) int { return y } - // karatsubaLen computes an approximation to the maximum k <= n such that // k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the // result is the largest number that can be divided repeatedly by 2 before @@ -382,7 +368,6 @@ func karatsubaLen(n int) int { return n << i } - func (z nat) mul(x, y nat) nat { m := len(x) n := len(y) @@ -450,7 +435,6 @@ func (z nat) mul(x, y nat) nat { return z.norm() } - // mulRange computes the product of all the unsigned integers in the // range [a, b] inclusively. If a > b (empty range), the result is 1. func (z nat) mulRange(a, b uint64) nat { @@ -469,7 +453,6 @@ func (z nat) mulRange(a, b uint64) nat { return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b)) } - // q = (x-r)/y, with 0 <= r < y func (z nat) divW(x nat, y Word) (q nat, r Word) { m := len(x) @@ -490,7 +473,6 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) { return } - func (z nat) div(z2, u, v nat) (q, r nat) { if len(v) == 0 { panic("division by zero") @@ -518,7 +500,6 @@ func (z nat) div(z2, u, v nat) (q, r nat) { return } - // q = (uIn-r)/v, with 0 <= r < y // Uses z as storage for q, and u as storage for r if possible. // See Knuth, Volume 2, section 4.3.1, Algorithm D. @@ -545,9 +526,14 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { u.clear() // D1. - shift := Word(leadingZeros(v[n-1])) - shlVW(v, v, shift) - u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift) + shift := leadingZeros(v[n-1]) + if shift > 0 { + // do not modify v, it may be used by another goroutine simultaneously + v1 := make(nat, n) + shlVU(v1, v, shift) + v = v1 + } + u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) // D2. for j := m; j >= 0; j-- { @@ -586,14 +572,12 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { } q = q.norm() - shrVW(u, u, shift) - shrVW(v, v, shift) + shrVU(u, u, shift) r = u.norm() return q, r } - // Length of x in bits. x must be normalized. func (x nat) bitLen() int { if i := len(x) - 1; i >= 0 { @@ -602,103 +586,253 @@ func (x nat) bitLen() int { return 0 } +// MaxBase is the largest number base accepted for string conversions. +const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1 -func hexValue(ch byte) int { - var d byte + +func hexValue(ch int) Word { + d := MaxBase + 1 // illegal base switch { case '0' <= ch && ch <= '9': d = ch - '0' - case 'a' <= ch && ch <= 'f': + case 'a' <= ch && ch <= 'z': d = ch - 'a' + 10 - case 'A' <= ch && ch <= 'F': + case 'A' <= ch && ch <= 'Z': d = ch - 'A' + 10 - default: - return -1 } - return int(d) + return Word(d) } - -// scan returns the natural number corresponding to the -// longest possible prefix of s representing a natural number in a -// given conversion base, the actual conversion base used, and the -// prefix length. The syntax of natural numbers follows the syntax -// of unsigned integer literals in Go. +// scan sets z to the natural number corresponding to the longest possible prefix +// read from r representing an unsigned integer in a given conversion base. +// It returns z, the actual conversion base used, and an error, if any. In the +// error case, the value of z is undefined. The syntax follows the syntax of +// unsigned integer literals in Go. // -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects -// base 2. Otherwise the selected base is 10. +// The base argument must be 0 or a value from 2 through MaxBase. If the base +// is 0, the string prefix determines the actual conversion base. A prefix of +// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a +// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. // -func (z nat) scan(s string, base int) (nat, int, int) { +func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) { + // reject illegal bases + if base < 0 || base == 1 || MaxBase < base { + return z, 0, os.NewError("illegal number base") + } + + // one char look-ahead + ch, _, err := r.ReadRune() + if err != nil { + return z, 0, err + } + // determine base if necessary - i, n := 0, len(s) + b := Word(base) if base == 0 { - base = 10 - if n > 0 && s[0] == '0' { - base, i = 8, 1 - if n > 1 { - switch s[1] { + b = 10 + if ch == '0' { + switch ch, _, err = r.ReadRune(); err { + case nil: + b = 8 + switch ch { case 'x', 'X': - base, i = 16, 2 + b = 16 case 'b', 'B': - base, i = 2, 2 + b = 2 } + if b == 2 || b == 16 { + if ch, _, err = r.ReadRune(); err != nil { + return z, 0, err + } + } + case os.EOF: + return z, 10, nil + default: + return z, 10, err } } } - // reject illegal bases or strings consisting only of prefix - if base < 2 || 16 < base || (base != 8 && i >= n) { - return z, 0, 0 - } - // convert string + // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb + // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd z = z.make(0) - for ; i < n; i++ { - d := hexValue(s[i]) - if 0 <= d && d < base { - z = z.mulAddWW(z, Word(base), Word(d)) + bb := Word(1) + dd := Word(0) + for max := _M / b; ; { + d := hexValue(ch) + if d >= b { + r.UnreadRune() // ch does not belong to number anymore + break + } + + if bb <= max { + bb *= b + dd = dd*b + d } else { + // bb * b would overflow + z = z.mulAddWW(z, bb, dd) + bb = b + dd = d + } + + if ch, _, err = r.ReadRune(); err != nil { + if err != os.EOF { + return z, int(b), err + } break } } - return z.norm(), base, i + switch { + case bb > 1: + // there was at least one mantissa digit + z = z.mulAddWW(z, bb, dd) + case base == 0 && b == 8: + // there was only the octal prefix 0 (possibly followed by digits > 7); + // return base 10, not 8 + return z, 10, nil + case base != 0 || b != 8: + // there was neither a mantissa digit nor the octal prefix 0 + return z, int(b), os.NewError("syntax error scanning number") + } + + return z.norm(), int(b), nil } +// Character sets for string conversion. +const ( + lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" + uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +) -// string converts x to a string for a given base, with 2 <= base <= 16. -// TODO(gri) in the style of the other routines, perhaps this should take -// a []byte buffer and return it -func (x nat) string(base int) string { - if base < 2 || 16 < base { - panic("illegal base") - } +// decimalString returns a decimal representation of x. +// It calls x.string with the charset "0123456789". +func (x nat) decimalString() string { + return x.string(lowercaseDigits[0:10]) +} - if len(x) == 0 { - return "0" +// string converts x to a string using digits from a charset; a digit with +// value d is represented by charset[d]. The conversion base is determined +// by len(charset), which must be >= 2. +func (x nat) string(charset string) string { + b := Word(len(charset)) + + // special cases + switch { + case b < 2 || b > 256: + panic("illegal base") + case len(x) == 0: + return string(charset[0]) } // allocate buffer for conversion - i := x.bitLen()/log2(Word(base)) + 1 // +1: round up + i := x.bitLen()/log2(b) + 1 // +1: round up s := make([]byte, i) - // don't destroy x + // special case: power of two bases can avoid divisions completely + if b == b&-b { + // shift is base-b digit size in bits + shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2 + mask := Word(1)<<shift - 1 + w := x[0] + nbits := uint(_W) // number of unprocessed bits in w + + // convert less-significant words + for k := 1; k < len(x); k++ { + // convert full digits + for nbits >= shift { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + // convert any partial leading digit and advance to next word + if nbits == 0 { + // no partial digit remaining, just advance + w = x[k] + nbits = _W + } else { + // partial digit in current (k-1) and next (k) word + w |= x[k] << nbits + i-- + s[i] = charset[w&mask] + + // advance + w = x[k] >> (shift - nbits) + nbits = _W - (shift - nbits) + } + } + + // convert digits of most-significant word (omit leading zeros) + for nbits >= 0 && w != 0 { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + return string(s[i:]) + } + + // general case: extract groups of digits by multiprecision division + + // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits + bb := Word(1) + ndigits := 0 + for max := Word(_M / b); bb <= max; bb *= b { + ndigits++ + } + + // preserve x, create local copy for use in repeated divisions q := nat(nil).set(x) + var r Word // convert - for len(q) > 0 { - i-- - var r Word - q, r = q.divW(q, Word(base)) - s[i] = "0123456789abcdef"[r] + if b == 10 { // hard-coding for 10 here speeds this up by 1.25x + for len(q) > 0 { + // extract least significant, base bb "digit" + q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW + if len(q) == 0 { + // skip leading zeros in most-significant group of digits + for j := 0; j < ndigits && r != 0; j++ { + i-- + s[i] = charset[r%10] + r /= 10 + } + } else { + for j := 0; j < ndigits; j++ { + i-- + s[i] = charset[r%10] + r /= 10 + } + } + } + } else { + for len(q) > 0 { + // extract least significant group of digits + q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW + if len(q) == 0 { + // skip leading zeros in most-significant group of digits + for j := 0; j < ndigits && r != 0; j++ { + i-- + s[i] = charset[r%b] + r /= b + } + } else { + for j := 0; j < ndigits; j++ { + i-- + s[i] = charset[r%b] + r /= b + } + } + } } return string(s[i:]) } - const deBruijn32 = 0x077CB531 var deBruijn32Lookup = []byte{ @@ -721,7 +855,7 @@ var deBruijn64Lookup = []byte{ func trailingZeroBits(x Word) int { // x & -x leaves only the right-most bit set in the word. Let k be the // index of that bit. Since only a single bit is set, the value is two - // to the power of k. Multipling by a power of two is equivalent to + // to the power of k. Multiplying by a power of two is equivalent to // left shifting, in this case by k bits. The de Bruijn constant is // such that all six bit, consecutive substrings are distinct. // Therefore, if we have a left shifted version of this constant we can @@ -739,7 +873,6 @@ func trailingZeroBits(x Word) int { return 0 } - // z = x << s func (z nat) shl(x nat, s uint) nat { m := len(x) @@ -750,13 +883,12 @@ func (z nat) shl(x nat, s uint) nat { n := m + int(s/_W) z = z.make(n + 1) - z[n] = shlVW(z[n-m:n], x, Word(s%_W)) + z[n] = shlVU(z[n-m:n], x, s%_W) z[0 : n-m].clear() return z.norm() } - // z = x >> s func (z nat) shr(x nat, s uint) nat { m := len(x) @@ -767,11 +899,45 @@ func (z nat) shr(x nat, s uint) nat { // n > 0 z = z.make(n) - shrVW(z, x[m-n:], Word(s%_W)) + shrVU(z, x[m-n:], s%_W) return z.norm() } +func (z nat) setBit(x nat, i uint, b uint) nat { + j := int(i / _W) + m := Word(1) << (i % _W) + n := len(x) + switch b { + case 0: + z = z.make(n) + copy(z, x) + if j >= n { + // no need to grow + return z + } + z[j] &^= m + return z.norm() + case 1: + if j >= n { + n = j + 1 + } + z = z.make(n) + copy(z, x) + z[j] |= m + // no need to normalize + return z + } + panic("set bit is not 0 or 1") +} + +func (z nat) bit(i uint) uint { + j := int(i / _W) + if j >= len(z) { + return 0 + } + return uint(z[j] >> (i % _W) & 1) +} func (z nat) and(x, y nat) nat { m := len(x) @@ -789,7 +955,6 @@ func (z nat) and(x, y nat) nat { return z.norm() } - func (z nat) andNot(x, y nat) nat { m := len(x) n := len(y) @@ -807,7 +972,6 @@ func (z nat) andNot(x, y nat) nat { return z.norm() } - func (z nat) or(x, y nat) nat { m := len(x) n := len(y) @@ -827,7 +991,6 @@ func (z nat) or(x, y nat) nat { return z.norm() } - func (z nat) xor(x, y nat) nat { m := len(x) n := len(y) @@ -847,10 +1010,10 @@ func (z nat) xor(x, y nat) nat { return z.norm() } - // greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2) -func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 } - +func greaterThan(x1, x2, y1, y2 Word) bool { + return x1 > y1 || x1 == y1 && x2 > y2 +} // modW returns x % d. func (x nat) modW(d Word) (r Word) { @@ -860,30 +1023,29 @@ func (x nat) modW(d Word) (r Word) { return divWVW(q, 0, x, d) } - -// powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd. -func (n nat) powersOfTwoDecompose() (q nat, k Word) { - if len(n) == 0 { - return n, 0 +// powersOfTwoDecompose finds q and k with x = q * 1<<k and q is odd, or q and k are 0. +func (x nat) powersOfTwoDecompose() (q nat, k int) { + if len(x) == 0 { + return x, 0 } - zeroWords := 0 - for n[zeroWords] == 0 { - zeroWords++ + // One of the words must be non-zero by definition, + // so this loop will terminate with i < len(x), and + // i is the number of 0 words. + i := 0 + for x[i] == 0 { + i++ } - // One of the words must be non-zero by invariant, therefore - // zeroWords < len(n). - x := trailingZeroBits(n[zeroWords]) + n := trailingZeroBits(x[i]) // x[i] != 0 - q = q.make(len(n) - zeroWords) - shrVW(q, n[zeroWords:], Word(x)) - q = q.norm() + q = make(nat, len(x)-i) + shrVU(q, x[i:], uint(n)) - k = Word(_W*zeroWords + x) + q = q.norm() + k = i*_W + n return } - // random creates a random integer in [0..limit), using the space in z if // possible. n is the bit length of limit. func (z nat) random(rand *rand.Rand, limit nat, n int) nat { @@ -914,7 +1076,6 @@ func (z nat) random(rand *rand.Rand, limit nat, n int) nat { return z.norm() } - // If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It // reuses the storage of z if possible. func (z nat) expNN(x, y, m nat) nat { @@ -983,7 +1144,6 @@ func (z nat) expNN(x, y, m nat) nat { return z } - // probablyPrime performs reps Miller-Rabin tests to check whether n is prime. // If it returns true, n is prime with probability 1 - 1/4^reps. // If it returns false, n is not prime. @@ -1050,7 +1210,7 @@ NextRandom: if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 { continue } - for j := Word(1); j < k; j++ { + for j := 1; j < k; j++ { y = y.mul(y, y) quotient, y = quotient.div(y, y, n) if y.cmp(nm1) == 0 { @@ -1066,7 +1226,6 @@ NextRandom: return true } - // bytes writes the value of z into buf using big-endian encoding. // len(buf) must be >= len(z)*_S. The value of z is encoded in the // slice buf[i:]. The number i of unused bytes at the beginning of @@ -1088,7 +1247,6 @@ func (z nat) bytes(buf []byte) (i int) { return } - // setBytes interprets buf as the bytes of a big-endian unsigned // integer, sets z to that value, and returns z. func (z nat) setBytes(buf []byte) nat { |