Files
2026-05-27 23:03:00 +08:00

958 lines
22 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements signed multi-precision integers.
// +build gmp
package gmp
// FIXME could we use Go's allocator (gmp can use a custom allocator)
// instead of using runtime.SetFinalizer to manage memory?
/*
#cgo LDFLAGS: -lgmp
#include <gmp.h>
#include <stdlib.h>
// gmp 5.0.0+ changed the type of the 3rd argument to mp_bitcnt_t,
// so, to support older versions, we wrap these two functions.
void _mpz_mul_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) {
mpz_mul_2exp(a, b, n);
}
void _mpz_div_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) {
mpz_div_2exp(a, b, n);
}
unsigned int _mpz_tstbit(mpz_ptr a, unsigned long n) {
return mpz_tstbit(a, n);
}
void _mpz_clrbit(mpz_ptr a, unsigned long n) {
mpz_clrbit(a, n);
}
void _mpz_setbit(mpz_ptr a, unsigned long n) {
mpz_setbit(a, n);
}
// Macros made into functions
int _mpz_sgn(mpz_t op) {
return mpz_sgn(op);
}
*/
import "C"
import (
"errors"
"fmt"
"io"
"math/rand"
"runtime"
"strings"
"unicode"
"unsafe"
)
// Some definited Ints for internal use only
var (
_Int0 = NewInt(0)
_Int1 = NewInt(1)
_Int10 = NewInt(10)
)
// An Int represents a signed multi-precision integer.
// The zero value for an Int represents the value 0.
type Int struct {
i C.mpz_t
init bool
}
// Finalizer - release the memory allocated to the mpz
func intFinalize(z *Int) {
if z.init {
runtime.SetFinalizer(z, nil)
C.mpz_clear(&z.i[0])
z.init = false
}
}
// Int promises that the zero value is a 0, but in gmp
// the zero value is a crash. To bridge the gap, the
// init bool says whether this is a valid gmp value.
// doinit initializes z.i if it needs it.
func (z *Int) doinit() {
if z.init {
return
}
z.init = true
C.mpz_init(&z.i[0])
runtime.SetFinalizer(z, intFinalize)
}
// Clear the allocated space used by the number
//
// This normally happens on a runtime.SetFinalizer call, but if you
// want immediate deallocation you can call it.
//
// NB This is not part of big.Int
func (z *Int) Clear() {
intFinalize(z)
}
// Sign returns:
//
// -1 if x < 0
// 0 if x == 0
// +1 if x > 0
//
func (z *Int) Sign() int {
z.doinit()
return int(C._mpz_sgn(&z.i[0]))
}
// SetInt64 sets z to x and returns z.
func (z *Int) SetInt64(x int64) *Int {
z.doinit()
// Test for truncation
y := C.long(x)
if int64(y) == x {
C.mpz_set_si(&z.i[0], y)
} else {
negative := false
if x < 0 {
x = -x
negative = true
}
C.mpz_import(&z.i[0], 1, 0, 8, 0, 0, unsafe.Pointer(&x))
if negative {
C.mpz_neg(&z.i[0], &z.i[0])
}
}
return z
}
// SetUint64 sets z to x and returns z.
func (z *Int) SetUint64(x uint64) *Int {
z.doinit()
// Test for truncation
y := C.ulong(x)
if uint64(y) == x {
C.mpz_set_ui(&z.i[0], y)
} else {
C.mpz_import(&z.i[0], 1, 0, 8, 0, 0, unsafe.Pointer(&x))
}
return z
}
// NewInt allocates and returns a new Int set to x.
func NewInt(x int64) *Int {
return new(Int).SetInt64(x)
}
// Set sets z to x and returns z.
func (z *Int) Set(x *Int) *Int {
z.doinit()
C.mpz_set(&z.i[0], &x.i[0])
return z
}
// Bits provides raw (unchecked but fast) access to x by returning its
// absolute value as a little-endian Word slice. The result and x share
// the same underlying array.
// Bits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
// func (z *Int) Bits() []Word {
// // FIXME not implemented
// return nil
// }
// SetBits provides raw (unchecked but fast) access to z by setting its
// value to abs, interpreted as a little-endian Word slice, and returning
// z. The result and abs share the same underlying array.
// SetBits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
// func (z *Int) SetBits(abs []Word) *Int {
// // FIXME not implemented
// return nil
// }
// Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Int) Abs(x *Int) *Int {
x.doinit()
z.doinit()
C.mpz_abs(&z.i[0], &x.i[0])
return z
}
// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
x.doinit()
z.doinit()
C.mpz_neg(&z.i[0], &x.i[0])
return z
}
// Add sets z to the sum x+y and returns z.
func (z *Int) Add(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_add(&z.i[0], &x.i[0], &y.i[0])
return z
}
// Sub sets z to the difference x-y and returns z.
func (z *Int) Sub(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_sub(&z.i[0], &x.i[0], &y.i[0])
return z
}
// Mul sets z to the product x*y and returns z.
func (z *Int) Mul(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_mul(&z.i[0], &x.i[0], &y.i[0])
return z
}
// MulRange sets z to the product of all integers
// in the range [a, b] inclusively and returns z.
// If a > b (empty range), the result is 1.
func (z *Int) MulRange(a, b int64) *Int {
switch {
case a > b:
return z.SetInt64(1) // empty range
case a <= 0 && b >= 0:
return z.SetInt64(0) // range includes 0
}
// a <= b && (b < 0 || a > 0)
// Can use gmp factorial routine if a = 1 and b >= 1
if a == 1 && b >= 1 {
C.mpz_fac_ui(&z.i[0], C.ulong(b))
} else {
// Slow
z.SetInt64(a)
for i := a + 1; i <= b; i++ {
C.mpz_mul_si(&z.i[0], &z.i[0], C.long(i))
}
}
return z
}
// Binomial sets z to the binomial coefficient of (n, k) and returns z.
func (z *Int) Binomial(n, k int64) *Int {
var a, b Int
a.MulRange(n-k+1, n)
b.MulRange(1, k)
return z.Quo(&a, &b)
}
// Quo sets z to the quotient x/y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Quo implements truncated division (like Go); see QuoRem for more details.
func (z *Int) Quo(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0])
return z
}
// Rem sets z to the remainder x%y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Rem implements truncated modulus (like Go); see QuoRem for more details.
func (z *Int) Rem(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0])
return z
}
// QuoRem sets z to the quotient x/y and r to the remainder x%y
// and returns the pair (z, r) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// QuoRem implements T-division and modulus (like Go):
//
// q = x/y with the result truncated to zero
// r = x - y*q
//
// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
// See DivMod for Euclidean division and modulus (unlike Go).
//
func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
x.doinit()
y.doinit()
r.doinit()
z.doinit()
C.mpz_tdiv_qr(&z.i[0], &r.i[0], &x.i[0], &y.i[0])
return z, r
}
// Div sets z to the quotient x/y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Div implements Euclidean division (unlike Go); see DivMod for more details.
func (z *Int) Div(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
switch y.Sign() {
case 1:
C.mpz_fdiv_q(&z.i[0], &x.i[0], &y.i[0])
case -1:
C.mpz_cdiv_q(&z.i[0], &x.i[0], &y.i[0])
case 0:
panic("Division by zero")
}
return z
}
// Mod sets z to the modulus x%y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
func (z *Int) Mod(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
switch y.Sign() {
case 1:
C.mpz_fdiv_r(&z.i[0], &x.i[0], &y.i[0])
case -1:
C.mpz_cdiv_r(&z.i[0], &x.i[0], &y.i[0])
case 0:
panic("Division by zero")
}
return z
}
// DivMod sets z to the quotient x div y and m to the modulus x mod y
// and returns the pair (z, m) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// DivMod implements Euclidean division and modulus (unlike Go):
//
// q = x div y such that
// m = x - y*q with 0 <= m < |q|
//
// (See Raymond T. Boute, ``The Euclidean definition of the functions
// div and mod''. ACM Transactions on Programming Languages and
// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
// ACM press.)
// See QuoRem for T-division and modulus (like Go).
//
func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
x.doinit()
y.doinit()
m.doinit()
z.doinit()
switch y.Sign() {
case 1:
C.mpz_fdiv_qr(&z.i[0], &m.i[0], &x.i[0], &y.i[0])
case -1:
C.mpz_cdiv_qr(&z.i[0], &m.i[0], &x.i[0], &y.i[0])
case 0:
panic("Division by zero")
}
return z, m
}
// Cmp compares z and y and returns:
//
// -1 if z < y
// 0 if z == y
// +1 if z > y
//
func (z *Int) Cmp(y *Int) (r int) {
z.doinit()
y.doinit()
r = int(C.mpz_cmp(&z.i[0], &y.i[0]))
if r < 0 {
r = -1
} else if r > 0 {
r = 1
}
return
}
// string returns z in the base given
func (z *Int) string(base int) string {
if z == nil {
return "<nil>"
}
z.doinit()
p := C.mpz_get_str(nil, C.int(base), &z.i[0])
s := C.GoString(p)
C.free(unsafe.Pointer(p))
return s
}
// String returns the decimal representation of z.
func (z *Int) String() string {
return z.string(10)
}
// Convert rune into base
//
// Note gmp says -ve bases make upper case
func baseForRune(ch rune) int {
switch ch {
case 'b':
return 2
case 'o':
return 8
case 'd', 's', 'v':
return 10
case 'x':
return 16
case 'X':
return -16
}
return 0 // unknown format
}
// write count copies of text to s
func writeMultiple(s fmt.State, text string, count int) {
if len(text) > 0 {
b := []byte(text)
for ; count > 0; count-- {
_, _ = s.Write(b)
}
}
}
// Format is a support routine for fmt.Formatter. It accepts
// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
// Also supported are the full suite of package fmt's format
// verbs for integral types, including '+', '-', and ' '
// for sign control, '#' for leading zero in octal and for
// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
// respectively, specification of minimum digits precision,
// output field width, space or zero padding, and left or
// right justification.
//
func (z *Int) Format(s fmt.State, ch rune) {
base := baseForRune(ch)
// special cases
switch {
case base == 0:
// unknown format
_, _ = fmt.Fprintf(s, "%%!%c(gmp.Int=%s)", ch, z.String())
return
case z == nil:
_, _ = fmt.Fprint(s, "<nil>")
return
}
// determine sign character
sign := ""
switch {
case z.Sign() < 0:
sign = "-"
case s.Flag('+'): // supersedes ' ' when both specified
sign = "+"
case s.Flag(' '):
sign = " "
}
// determine prefix characters for indicating output base
prefix := ""
if s.Flag('#') {
switch ch {
case 'o': // octal
prefix = "0"
case 'x': // hexadecimal
prefix = "0x"
case 'X':
prefix = "0X"
}
}
// determine digits with base set by len(cs) and digit characters from cs
digits := z.string(base)
if digits[0] == '-' {
digits = digits[1:]
}
// number of characters for the three classes of number padding
var left int // space characters to left of digits for right justification ("%8d")
var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
var right int // space characters to right of digits for left justification ("%-8d")
// determine number padding from precision: the least number of digits to output
precision, precisionSet := s.Precision()
if precisionSet {
switch {
case len(digits) < precision:
zeroes = precision - len(digits) // count of zero padding
case digits == "0" && precision == 0:
return // print nothing if zero value (z == 0) and zero precision ("." or ".0")
}
}
// determine field pad from width: the least number of characters to output
length := len(sign) + len(prefix) + zeroes + len(digits)
if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
switch d := width - length; {
case s.Flag('-'):
// pad on the right with spaces; supersedes '0' when both specified
right = d
case s.Flag('0') && !precisionSet:
// pad with zeroes unless precision also specified
zeroes = d
default:
// pad on the left with spaces
left = d
}
}
// print number as [left pad][sign][prefix][zero pad][digits][right pad]
writeMultiple(s, " ", left)
writeMultiple(s, sign, 1)
writeMultiple(s, prefix, 1)
writeMultiple(s, "0", zeroes)
writeMultiple(s, digits, 1)
writeMultiple(s, " ", right)
}
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
s.SkipSpace() // skip leading space characters
base := 0
switch ch {
case 'b':
base = 2
case 'o':
base = 8
case 'd':
base = 10
case 'x', 'X':
base = 16
case 's', 'v':
// let scan determine the base
default:
return errors.New("Int.Scan: invalid verb")
}
charset := "0123456789abcdef"
if base != 0 {
charset = charset[:base]
}
// Read the number into in
in := make([]byte, 0, 16)
var err error
var n int
for {
ch, n, err = s.ReadRune()
if err == io.EOF {
break
}
if err != nil {
return err
}
if n > 1 {
// Wide character - must be the end
err = s.UnreadRune()
if err != nil {
return err
}
break
}
ch = unicode.ToLower(ch)
if len(in) == 0 {
if ch == '+' {
// Skip leading + as gmp doesn't understand them
continue
}
if ch == '-' {
goto ok
}
}
if len(in) == 1 && base == 0 {
if ch == 'b' || ch == 'x' {
goto ok
}
}
if !strings.ContainsRune(charset, ch) {
// Bad character - end
err = s.UnreadRune()
if err != nil {
return err
}
break
}
ok:
in = append(in, byte(ch))
}
// Use GMP to convert it as it is very efficient for large numbers
z.doinit()
// null terminate for C
in = append(in, 0)
if C.mpz_set_str(&z.i[0], (*C.char)(unsafe.Pointer(&in[0])), C.int(base)) < 0 {
return errors.New("Int.Scan: failed")
}
return nil
}
// Int64 returns the int64 representation of z.
// If z cannot be represented in an int64, the result is undefined.
func (z *Int) Int64() (y int64) {
if !z.init {
return
}
if C.mpz_fits_slong_p(&z.i[0]) != 0 {
return int64(C.mpz_get_si(&z.i[0]))
}
// Undefined result if > 64 bits
if z.BitLen() > 64 {
return
}
C.mpz_export(unsafe.Pointer(&y), nil, -1, 8, 0, 0, &z.i[0])
if z.Sign() < 0 {
y = -y
}
return
}
// Uint64 returns the uint64 representation of z.
// If z cannot be represented in a uint64, the result is undefined.
func (z *Int) Uint64() (y uint64) {
if !z.init {
return
}
if C.mpz_fits_ulong_p(&z.i[0]) != 0 {
return uint64(C.mpz_get_ui(&z.i[0]))
}
// Undefined result if > 64 bits
if z.BitLen() > 64 {
return
}
C.mpz_export(unsafe.Pointer(&y), nil, -1, 8, 0, 0, &z.i[0])
return
}
// SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. If SetString fails,
// the value of z is undefined but the returned value is nil.
//
// 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 *Int) SetString(s string, base int) (*Int, bool) {
z.doinit()
if base != 0 && (base < 2 || base > 36) {
return nil, false
}
// Skip leading + as mpz_set_str doesn't understand them
if len(s) > 1 && s[0] == '+' {
s = s[1:]
}
// mpz_set_str incorrectly parses "0x" and "0b" as valid
if base == 0 && len(s) == 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X' || s[1] == 'b' || s[1] == 'B') {
return nil, false
}
p := C.CString(s)
defer C.free(unsafe.Pointer(p))
if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {
return nil, false
}
return z, true // err == io.EOF => scan consumed all of s
}
// SetBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func (z *Int) SetBytes(buf []byte) *Int {
z.doinit()
if len(buf) == 0 {
z.SetInt64(0)
} else {
C.mpz_import(&z.i[0], C.size_t(len(buf)), 1, 1, 1, 0, unsafe.Pointer(&buf[0]))
}
return z
}
// Bytes returns the absolute value of z as a big-endian byte slice.
func (z *Int) Bytes() []byte {
b := make([]byte, 1+(z.BitLen()+7)/8)
n := C.size_t(len(b))
C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0])
return b[0:n]
}
// BitLen returns the length of the absolute value of z in bits.
// The bit length of 0 is 0.
func (z *Int) BitLen() int {
z.doinit()
if z.Sign() == 0 {
return 0
}
return int(C.mpz_sizeinbase(&z.i[0], 2))
}
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
// If y <= 0, the result is 1; if m == nil or m == 0, z = x**y.
// See Knuth, volume 2, section 4.6.3.
func (z *Int) Exp(x, y, m *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
if y.Sign() <= 0 {
z.SetInt64(1)
return z
}
if m == nil || m.Sign() == 0 {
C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]))
} else {
m.doinit()
C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0])
}
return z
}
// GCD sets z to the greatest common divisor of a and b, which both must
// be > 0, and returns z.
// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
// If either a or b is <= 0, GCD sets z = x = y = 0.
func (z *Int) GCD(x, y, a, b *Int) *Int {
z.doinit()
a.doinit()
b.doinit()
if a.Sign() <= 0 || b.Sign() <= 0 {
z.SetInt64(0)
if x != nil {
x.SetInt64(0)
}
if y != nil {
y.SetInt64(0)
}
} else if x == nil && y == nil {
C.mpz_gcd(&z.i[0], &a.i[0], &b.i[0])
} else {
if x != nil {
x.doinit()
} else {
x = _Int0
}
if y != nil {
y.doinit()
} else {
y = _Int0
}
C.mpz_gcdext(&z.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0])
}
return z
}
// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
// If it returns true, z is prime with probability 1 - 1/4^n.
// If it returns false, z is not prime.
func (z *Int) ProbablyPrime(n int) bool {
z.doinit()
return int(C.mpz_probab_prime_p(&z.i[0], C.int(n))) > 0
}
// 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.doinit()
// Get rid of n <= 0 case
if n.Sign() <= 0 {
z.SetInt64(0)
return z
}
// Make a copy of n if aliased
t := n
aliased := false
if n == z {
aliased = true
t = new(Int).Set(n)
}
// Work out bit sizes and masks
bits := n.BitLen() // >= 1
nwords := (bits + 31) / 32 // >= 1
bitLengthOfMSW := uint(bits % 32)
if bitLengthOfMSW == 0 {
bitLengthOfMSW = 32
}
mask := uint32((1 << bitLengthOfMSW) - 1)
words := make([]uint32, nwords)
for {
// Make a most significant first array of random bytes
for i := 0; i < nwords; i++ {
words[i] = rnd.Uint32()
}
// Mask out the top bits so this is only just bigger than n
words[0] &= mask
C.mpz_import(&z.i[0], C.size_t(len(words)), 1, 4, 0, 0, unsafe.Pointer(&words[0]))
// Exit if z < n - should take ~1.5 iterations of loop on average
if z.Cmp(t) < 0 {
break
}
}
if aliased {
t.Clear()
}
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 {
g.doinit()
p.doinit()
z.doinit()
C.mpz_invert(&z.i[0], &g.i[0], &p.i[0])
return z
}
// Lsh sets z = x << n and returns z.
func (z *Int) Lsh(x *Int, n uint) *Int {
x.doinit()
z.doinit()
C._mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(n))
return z
}
// Rsh sets z = x >> n and returns z.
func (z *Int) Rsh(x *Int, n uint) *Int {
x.doinit()
z.doinit()
C._mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(n))
return z
}
// Bit returns the value of the i'th bit of z. That is, it
// returns (z>>i)&1. The bit index i must be >= 0.
func (z *Int) Bit(i int) uint {
z.doinit()
return uint(C._mpz_tstbit(&z.i[0], C.ulong(i)))
}
// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
// That is, if b is 1 SetBit sets z = x | (1 << i);
// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
// SetBit will panic.
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
if z != x {
z.Set(x)
}
if b == 0 {
C._mpz_clrbit(&z.i[0], C.ulong(i))
} else {
C._mpz_setbit(&z.i[0], C.ulong(i))
}
return z
}
// And sets z = x & y and returns z.
func (z *Int) And(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_and(&z.i[0], &x.i[0], &y.i[0])
return z
}
// AndNot sets z = x &^ y and returns z.
func (z *Int) AndNot(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
t := z
aliased := false
if z == y || z == x {
aliased = true
t = new(Int).Set(y)
}
C.mpz_com(&t.i[0], &y.i[0])
C.mpz_and(&z.i[0], &x.i[0], &t.i[0])
if aliased {
t.Clear()
}
return z
}
// Or sets z = x | y and returns z.
func (z *Int) Or(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_ior(&z.i[0], &x.i[0], &y.i[0])
return z
}
// Xor sets z = x ^ y and returns z.
func (z *Int) Xor(x, y *Int) *Int {
x.doinit()
y.doinit()
z.doinit()
C.mpz_xor(&z.i[0], &x.i[0], &y.i[0])
return z
}
// Not sets z = ^x and returns z.
func (z *Int) Not(x *Int) *Int {
x.doinit()
z.doinit()
C.mpz_com(&z.i[0], &x.i[0])
return z
}
// Gob codec version. Permits backward-compatible changes to the encoding.
const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
func (z *Int) GobEncode() ([]byte, error) {
buf := make([]byte, 2+(z.BitLen()+7)/8)
n := C.size_t(len(buf) - 1)
C.mpz_export(unsafe.Pointer(&buf[1]), &n, 1, 1, 1, 0, &z.i[0])
b := intGobVersion << 1 // make space for sign bit
if z.Sign() < 0 {
b |= 1
}
buf[0] = b
return buf[:n+1], nil
}
// GobDecode implements the gob.GobDecoder interface.
func (z *Int) GobDecode(buf []byte) error {
if len(buf) == 0 {
return errors.New("Int.GobDecode: no data")
}
b := buf[0]
if b>>1 != intGobVersion {
return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
}
z.SetBytes(buf[1:])
if b&1 != 0 {
C.mpz_neg(&z.i[0], &z.i[0])
}
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (z *Int) MarshalJSON() ([]byte, error) {
// TODO(gri): get rid of the []byte/string conversions
return []byte(z.String()), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (z *Int) UnmarshalJSON(x []byte) error {
// TODO(gri): get rid of the []byte/string conversions
_, ok := z.SetString(string(x), 0)
if !ok {
return fmt.Errorf("math/big: cannot unmarshal %s into a *gmp.Int", x)
}
return nil
}