init: v1.0.0
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,104 @@
|
||||
Gmp
|
||||
===
|
||||
|
||||
[](https://godoc.org/github.com/ncw/gmp)
|
||||
[](https://travis-ci.org/ncw/gmp)
|
||||
|
||||
This package provides a drop in replacement for Go's built in
|
||||
[math/big](http://golang.org/pkg/math/big/) big integer package using
|
||||
the [GNU Multiprecision Library](http://gmplib.org/) (GMP).
|
||||
|
||||
GMP is very much faster than Go's math/big however it is an external C
|
||||
library with all the problems that entails (cgo, dependencies etc)
|
||||
|
||||
This library was made by taking the [cgo example of wrapping
|
||||
GMP](http://golang.org/misc/cgo/gmp/gmp.go) from the Go source and
|
||||
doing the following to it
|
||||
|
||||
* Copying the implementation from misc/cgo/gmp/gmp.go
|
||||
* Copying the documentation from src/pkg/math/big/int.go
|
||||
* Additional implementation of missing methods
|
||||
* Bug fixes for existing implementations
|
||||
* Making it passes the test suite from src/pkg/math/big/int_test.go
|
||||
* Adding memory management
|
||||
* Fix problems on 32 bit platforms when using `int64` values which don't fit into a `C.long`
|
||||
* Implementing Rat support making it pass src/pkg/math/big/rat_test.go
|
||||
|
||||
See here for package docs
|
||||
|
||||
* https://godoc.org/github.com/ncw/gmp
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
Use go to install the library
|
||||
|
||||
go get github.com/ncw/gmp
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
See here for full package docs
|
||||
|
||||
* http://go.pkgdoc.org/github.com/ncw/gmp
|
||||
|
||||
To use as in a drop in replacement for math/big, replace
|
||||
|
||||
import "math/big"
|
||||
|
||||
With
|
||||
|
||||
import big "github.com/ncw/gmp"
|
||||
|
||||
Features that aren't part of math/big are clearly marked and if you
|
||||
are using those, then I suggest you import as
|
||||
|
||||
import "github.com/ncw/gmp"
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
To run the tests use
|
||||
|
||||
go test github.com/ncw/gmp
|
||||
|
||||
The tests have been copied from the tests for the math/big library in
|
||||
the Go source and modified as little as possible so it should be 100%
|
||||
compatible.
|
||||
|
||||
Differences
|
||||
-----------
|
||||
|
||||
Here are the differences between math/big and this package
|
||||
|
||||
* `Int.Bits` and `Int.SetBits` not implemented
|
||||
* `Rat.Num()` and `Rat.Denom()` return a copy not a reference, so
|
||||
* If you want to set them use the new methods `Rat.SetNum()` and `Rat.SetDenom()`
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
As this contains a great deal of code copied from the Go source it is
|
||||
licenced identically to the Go source itself - see the LICENSE file
|
||||
for details.
|
||||
|
||||
Contact and support
|
||||
-------------------
|
||||
|
||||
The project website is at:
|
||||
|
||||
* https://github.com/ncw/gmp
|
||||
|
||||
There you can file bug reports, ask for help or contribute patches.
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* [The Go team](http://golang.org/AUTHORS)
|
||||
* Nick Craig-Wood <nick@craig-wood.com>
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Bert Gijsbers <gijhub@gmail.com>
|
||||
@@ -0,0 +1,140 @@
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkSwapO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
c := NewInt(0)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
c.Set(a)
|
||||
a.Set(b)
|
||||
b.Set(c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSwapX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Swap(b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddUintO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
b.SetUint64(uint64(i))
|
||||
a.Add(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddUintX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.AddUint32(a, uint32(i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulInt0(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
b.SetInt64(1)
|
||||
a.Mul(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulIntX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.MulInt32(a, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddMulO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
c := NewInt(0)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Add(a, c)
|
||||
b.Mul(b, a)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddMulX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
c := NewInt(0)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
b.AddMul(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCmpIntO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.SetInt64(int64(i))
|
||||
b.Cmp(a)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCmpIntX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.CmpInt32(int32(i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCmpAbsO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(2)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Abs(a)
|
||||
b.Abs(b)
|
||||
a.Cmp(b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCmpAbsX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
b := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.CmpAbs(b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetIntO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Int64()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetIntX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Int32()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetUintO(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Uint64()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetUintX(bench *testing.B) {
|
||||
a := NewInt(1)
|
||||
for i := bench.N; i > 0; i-- {
|
||||
a.Uint32()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Make a n digit number
|
||||
func nDigitNumberGmp(digits int64) *Int {
|
||||
x := NewInt(10)
|
||||
n := NewInt(digits)
|
||||
one := NewInt(1)
|
||||
x.Exp(x, n, nil)
|
||||
x.Sub(x, one)
|
||||
return x
|
||||
}
|
||||
|
||||
func TestPow(t *testing.T) {
|
||||
|
||||
n, _ := NewInt(1).SetString("151787717184422252307365020658866150659139813606887864663574443176328014948429913407344055128026662986925949147541666619511526142491196760869802510776788353419093645990851372578901256051814507665042918937343846064086867942964225457691185973174205523727877484153730596121423900155549117133518141928295347285789", 10)
|
||||
m, _ := NewInt(1).SetString("15178771718442225230736502065886615065913981360688786466357444317632801494842991340734405512802666298692594914754166661951152614249119676086980251077678835341909364599085137257890125605181450766504291893734384606408686794296422545769118597317420552372787748415373059612142390015554911713351814192829534728578", 10)
|
||||
d, _ := NewInt(1).SetString("141787717184422252307365020658866150659139813606887864663574443176328014948429913407344055128026662986925949147541666619511526142491196760869802510776788353419093645990851372578901256051814507665042918937343846064086867942964225457691185973174205523727877484153730596121423900155549117133518141928295347285789", 10)
|
||||
c := NewInt(1)
|
||||
|
||||
cnt := 10000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
c.Exp(m, d, n)
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
fmt.Printf("Sign %d times\n", cnt)
|
||||
fmt.Printf("Used time: %d ms, %d pcs/s\n", elapsed.Milliseconds(), int(float64(cnt)/float64(elapsed.Milliseconds())*1000))
|
||||
|
||||
}
|
||||
|
||||
func benchmarkGmpAddN(b *testing.B, digits int64) {
|
||||
x := nDigitNumberGmp(digits)
|
||||
y := nDigitNumberGmp(digits)
|
||||
z := NewInt(0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.Add(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGmpAdd1(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 10)
|
||||
}
|
||||
func BenchmarkGmpAdd10(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 10)
|
||||
}
|
||||
func BenchmarkGmpAdd100(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 100)
|
||||
}
|
||||
func BenchmarkGmpAdd1000(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 1000)
|
||||
}
|
||||
func BenchmarkGmpAdd10000(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 10000)
|
||||
}
|
||||
func BenchmarkGmpAdd100000(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 100000)
|
||||
}
|
||||
func BenchmarkGmpAdd1000000(b *testing.B) {
|
||||
benchmarkGmpAddN(b, 1000000)
|
||||
}
|
||||
|
||||
func benchmarkGmpMulN(b *testing.B, digits int64) {
|
||||
x := nDigitNumberGmp(digits)
|
||||
y := nDigitNumberGmp(digits)
|
||||
z := NewInt(0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.Mul(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGmpMul1(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 10)
|
||||
}
|
||||
func BenchmarkGmpMul10(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 10)
|
||||
}
|
||||
func BenchmarkGmpMul100(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 100)
|
||||
}
|
||||
func BenchmarkGmpMul1000(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 1000)
|
||||
}
|
||||
func BenchmarkGmpMul10000(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 10000)
|
||||
}
|
||||
func BenchmarkGmpMul100000(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 100000)
|
||||
}
|
||||
func BenchmarkGmpMul1000000(b *testing.B) {
|
||||
benchmarkGmpMulN(b, 1000000)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Make a n digit number
|
||||
func nDigitNumberMathBig(digits int64) *big.Int {
|
||||
x := big.NewInt(10)
|
||||
n := big.NewInt(digits)
|
||||
one := big.NewInt(1)
|
||||
x.Exp(x, n, nil)
|
||||
x.Sub(x, one)
|
||||
return x
|
||||
}
|
||||
|
||||
func benchmarkMathBigAddN(b *testing.B, digits int64) {
|
||||
x := nDigitNumberMathBig(digits)
|
||||
y := nDigitNumberMathBig(digits)
|
||||
z := big.NewInt(0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.Add(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMathBigAdd1(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 10)
|
||||
}
|
||||
func BenchmarkMathBigAdd10(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 10)
|
||||
}
|
||||
func BenchmarkMathBigAdd100(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 100)
|
||||
}
|
||||
func BenchmarkMathBigAdd1000(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 1000)
|
||||
}
|
||||
func BenchmarkMathBigAdd10000(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 10000)
|
||||
}
|
||||
func BenchmarkMathBigAdd100000(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 100000)
|
||||
}
|
||||
func BenchmarkMathBigAdd1000000(b *testing.B) {
|
||||
benchmarkMathBigAddN(b, 1000000)
|
||||
}
|
||||
|
||||
func benchmarkMathBigMulN(b *testing.B, digits int64) {
|
||||
x := nDigitNumberMathBig(digits)
|
||||
y := nDigitNumberMathBig(digits)
|
||||
z := big.NewInt(0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.Mul(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMathBigMul1(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 10)
|
||||
}
|
||||
func BenchmarkMathBigMul10(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 10)
|
||||
}
|
||||
func BenchmarkMathBigMul100(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 100)
|
||||
}
|
||||
func BenchmarkMathBigMul1000(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 1000)
|
||||
}
|
||||
func BenchmarkMathBigMul10000(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 10000)
|
||||
}
|
||||
func BenchmarkMathBigMul100000(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 100000)
|
||||
}
|
||||
func BenchmarkMathBigMul1000000(b *testing.B) {
|
||||
benchmarkMathBigMulN(b, 1000000)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
// Package gmp implements multi-precision arithmetic (big numbers).
|
||||
//
|
||||
// This package provides a drop in replacement for Go's built in
|
||||
// math/big integer package using the GNU Multiprecision Library (GMP)
|
||||
// to implement the operations.
|
||||
//
|
||||
// GMP is very much faster than Go's math/big however it is an
|
||||
// external C library with all the problems that entails (cgo,
|
||||
// dependencies etc)
|
||||
//
|
||||
// The following numeric types are supported:
|
||||
//
|
||||
// - Int signed integers
|
||||
// - Rat rational numbers are NOT yet supported
|
||||
//
|
||||
// Methods are typically of the form:
|
||||
//
|
||||
// func (z *Int) Op(x, y *Int) *Int (similar for *Rat)
|
||||
//
|
||||
// and implement operations z = x Op y with the result as receiver; if it
|
||||
// is one of the operands it may be overwritten (and its memory reused).
|
||||
// To enable chaining of operations, the result is also returned. Methods
|
||||
// returning a result other than *Int or *Rat take one of the operands as
|
||||
// the receiver.
|
||||
//
|
||||
package gmp
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// func ExampleRat_SetString() {
|
||||
// r := new(big.Rat)
|
||||
// r.SetString("355/113")
|
||||
// fmt.Println(r.FloatString(3))
|
||||
// // Output: 3.142
|
||||
// }
|
||||
|
||||
func ExampleInt_SetString() {
|
||||
i := new(Int)
|
||||
i.SetString("644", 8) // octal
|
||||
fmt.Println(i)
|
||||
// Output: 420
|
||||
}
|
||||
|
||||
// func ExampleRat_Scan() {
|
||||
// // The Scan function is rarely used directly;
|
||||
// // the fmt package recognizes it as an implementation of fmt.Scanner.
|
||||
// r := new(Rat)
|
||||
// _, err := fmt.Sscan("1.5000", r)
|
||||
// if err != nil {
|
||||
// log.Println("error scanning value:", err)
|
||||
// } else {
|
||||
// fmt.Println(r)
|
||||
// }
|
||||
// // Output: 3/2
|
||||
// }
|
||||
|
||||
func ExampleInt_Scan() {
|
||||
// The Scan function is rarely used directly;
|
||||
// the fmt package recognizes it as an implementation of fmt.Scanner.
|
||||
i := new(Int)
|
||||
_, err := fmt.Sscan("18446744073709551617", i)
|
||||
if err != nil {
|
||||
log.Println("error scanning value:", err)
|
||||
} else {
|
||||
fmt.Println(i)
|
||||
}
|
||||
// Output: 18446744073709551617
|
||||
}
|
||||
@@ -0,0 +1,957 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// Implement extra functionality not in big.Int.
|
||||
//
|
||||
// Because the underlying C compiler may use 32-bit longs we
|
||||
// use 32-bit integers here for maximum portability and speed.
|
||||
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lgmp
|
||||
#include <gmp.h>
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Sqrt sets x to the truncated integer part of the square root of x
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) Sqrt(x *Int) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_sqrt(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// Swap exchanges the values of z and x and returns the new z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) Swap(x *Int) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_swap(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// AddUint32 sets z to the sum x+y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) AddUint32(x *Int, y uint32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_add_ui(&z.i[0], &x.i[0], C.ulong(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// SubUint32 sets z to the difference x-y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) SubUint32(x *Int, y uint32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_sub_ui(&z.i[0], &x.i[0], C.ulong(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// Uint32Sub sets z to the difference x-y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) Uint32Sub(x uint32, y *Int) *Int {
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpz_ui_sub(&z.i[0], C.ulong(x), &y.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// MulUint32 sets z to the product x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) MulUint32(x *Int, y uint32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_mul_ui(&z.i[0], &x.i[0], C.ulong(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// MulInt32 sets z to the product x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) MulInt32(x *Int, y int32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_mul_si(&z.i[0], &x.i[0], C.long(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// AddMul sets z to z + x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) AddMul(x, y *Int) *Int {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpz_addmul(&z.i[0], &x.i[0], &y.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// AddMulUint32 sets z to z + x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) AddMulUint32(x *Int, y uint32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_addmul_ui(&z.i[0], &x.i[0], C.ulong(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// SubMul sets z to z - x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) SubMul(x, y *Int) *Int {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpz_submul(&z.i[0], &x.i[0], &y.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// SubMulUint32 sets z to z - x*y and returns z.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) SubMulUint32(x *Int, y uint32) *Int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
C.mpz_submul_ui(&z.i[0], &x.i[0], C.ulong(y))
|
||||
return z
|
||||
}
|
||||
|
||||
// compared reduces the result of a GMP comparison to one of {-1, 0, 1}.
|
||||
func compared(i C.int) int {
|
||||
if i > 0 {
|
||||
return 1
|
||||
} else if i < 0 {
|
||||
return -1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// CmpUint32 compares z and x and returns:
|
||||
//
|
||||
// -1 if z < x
|
||||
// 0 if z == x
|
||||
// +1 if z > x
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) CmpUint32(x uint32) int {
|
||||
z.doinit()
|
||||
return compared(C._mpz_cmp_ui(&z.i[0], C.ulong(x)))
|
||||
}
|
||||
|
||||
// CmpInt32 compares z and x and returns:
|
||||
//
|
||||
// -1 if z < x
|
||||
// 0 if z == x
|
||||
// +1 if z > x
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) CmpInt32(x int32) int {
|
||||
z.doinit()
|
||||
return compared(C._mpz_cmp_si(&z.i[0], C.long(x)))
|
||||
}
|
||||
|
||||
// CmpAbs compares |z| and |x| and returns:
|
||||
//
|
||||
// -1 if |z| < |x|
|
||||
// 0 if |z| == |x|
|
||||
// +1 if |z| > |x|
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) CmpAbs(x *Int) int {
|
||||
x.doinit()
|
||||
z.doinit()
|
||||
return compared(C.mpz_cmpabs(&z.i[0], &x.i[0]))
|
||||
}
|
||||
|
||||
// CmpAbsUint32 compares |z| and |x| and returns:
|
||||
//
|
||||
// -1 if |z| < |x|
|
||||
// 0 if |z| == |x|
|
||||
// +1 if |z| > |x|
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) CmpAbsUint32(x uint32) int {
|
||||
z.doinit()
|
||||
return compared(C.mpz_cmpabs_ui(&z.i[0], C.ulong(x)))
|
||||
}
|
||||
|
||||
// Uint32 returns the uint32 representation of z, if z fits into a uint32.
|
||||
// If z is too big then the least significant bits that do fit are returned.
|
||||
// The sign of z is ignored, only the absolute value is used.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) Uint32() uint32 {
|
||||
z.doinit()
|
||||
return uint32(C.mpz_get_ui(&z.i[0]))
|
||||
}
|
||||
|
||||
// Int32 returns the int32 representation of z, if z fits into a signed int32.
|
||||
// If z is too big to fit in a int32 then the result is undefined.
|
||||
//
|
||||
// NB This is not part of big.Int
|
||||
func (z *Int) Int32() int32 {
|
||||
z.doinit()
|
||||
return int32(C.mpz_get_si(&z.i[0]))
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
// 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.
|
||||
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
// Test extra functionality
|
||||
|
||||
package gmp
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type binaryFun func(a, b int64) bool
|
||||
type ternaryFun func(a, b, c int64) bool
|
||||
|
||||
var random *rand.Rand
|
||||
var perFuncTests []int
|
||||
|
||||
func init() {
|
||||
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
perFuncTests = random.Perm(50)
|
||||
}
|
||||
|
||||
func randoms(num int, bits int) <-chan int64 {
|
||||
channel := make(chan int64)
|
||||
go func(out chan<- int64) {
|
||||
for _, i := range random.Perm(num) {
|
||||
ran := random.Int63n(1<<uint(bits-1) - 1)
|
||||
if i&1 == 1 {
|
||||
ran = -ran
|
||||
}
|
||||
out <- ran
|
||||
}
|
||||
close(out)
|
||||
}(channel)
|
||||
return channel
|
||||
}
|
||||
|
||||
func absi(i int64) int64 {
|
||||
if i < 0 {
|
||||
return -i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func cmpi(a, b int64) int {
|
||||
if a < b {
|
||||
return -1
|
||||
}
|
||||
if a > b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func testBinary(t *testing.T, name string, fun binaryFun, maxBits int) {
|
||||
small := [...]int64{0, 1, -1, 2, -2, 3, -3}
|
||||
for _, x := range small {
|
||||
for _, y := range small {
|
||||
if !fun(x, y) {
|
||||
t.Errorf("%s failed for %v and %v", name, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
for x := range randoms(10, maxBits) {
|
||||
for y := range randoms(10, maxBits) {
|
||||
if !fun(x, y) {
|
||||
t.Errorf("%s failed for %v and %v", name, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTernary(t *testing.T, name string, fun ternaryFun) {
|
||||
small := [...]int64{0, 1, -1, 2, -2, 3, -3}
|
||||
for _, x := range small {
|
||||
for _, y := range small {
|
||||
for _, z := range small {
|
||||
if !fun(x, y, z) {
|
||||
t.Errorf("%s failed for %v, %v and %v", name, x, y, z)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
num, bits := 6, 30
|
||||
for x := range randoms(num, bits) {
|
||||
for y := range randoms(num, bits) {
|
||||
for z := range randoms(num, bits) {
|
||||
if !fun(x, y, z) {
|
||||
t.Errorf("%s failed for %v, %v and %v", name, x, y, z)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwap(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
b := NewInt(j)
|
||||
a.Swap(b)
|
||||
return i == b.Int64() && j == a.Int64()
|
||||
}
|
||||
testBinary(t, "Swap", fun, 64)
|
||||
}
|
||||
|
||||
func TestAddMul(t *testing.T) {
|
||||
fun := func(i, j, k int64) bool {
|
||||
a := NewInt(i)
|
||||
return a.AddMul(NewInt(j), NewInt(k)).Int64() == i+j*k
|
||||
}
|
||||
testTernary(t, "AddMul", fun)
|
||||
}
|
||||
|
||||
func TestAddUint32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.AddUint32(a, k).Int64() == i+int64(k)
|
||||
}
|
||||
testBinary(t, "AddUint32", fun, 62)
|
||||
}
|
||||
|
||||
func TestSubUint32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.SubUint32(a, k).Int64() == i-int64(k)
|
||||
}
|
||||
testBinary(t, "SubUint32", fun, 62)
|
||||
}
|
||||
|
||||
func TestUint32Sub(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.Uint32Sub(k, a).Int64() == int64(k)-i
|
||||
}
|
||||
testBinary(t, "Uint32Sub", fun, 62)
|
||||
}
|
||||
|
||||
func TestMulUint32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.MulUint32(a, k).Int64() == i*int64(k)
|
||||
}
|
||||
testBinary(t, "MulUint32", fun, 30)
|
||||
}
|
||||
|
||||
func TestMulInt32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := int32(j)
|
||||
return a.MulInt32(a, k).Int64() == i*int64(k)
|
||||
}
|
||||
testBinary(t, "MulInt32", fun, 30)
|
||||
}
|
||||
|
||||
func TestAddMulUint32(t *testing.T) {
|
||||
fun := func(i, j, k int64) bool {
|
||||
a := NewInt(i)
|
||||
n := uint32(k)
|
||||
return a.AddMulUint32(NewInt(j), n).Int64() == i+j*int64(n)
|
||||
}
|
||||
testTernary(t, "AddMulUint32", fun)
|
||||
}
|
||||
|
||||
func TestSubMul(t *testing.T) {
|
||||
fun := func(i, j, k int64) bool {
|
||||
a := NewInt(i)
|
||||
return a.SubMul(NewInt(j), NewInt(k)).Int64() == i-j*k
|
||||
}
|
||||
testTernary(t, "SubMul", fun)
|
||||
}
|
||||
|
||||
func TestSubMulUint32(t *testing.T) {
|
||||
fun := func(i, j, k int64) bool {
|
||||
a := NewInt(i)
|
||||
n := uint32(k)
|
||||
return a.SubMulUint32(NewInt(j), n).Int64() == i-j*int64(n)
|
||||
}
|
||||
testTernary(t, "SubMulUint32", fun)
|
||||
}
|
||||
|
||||
func TestCmpUint32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.CmpUint32(k) == cmpi(i, int64(k))
|
||||
}
|
||||
testBinary(t, "CmpUint32", fun, 64)
|
||||
}
|
||||
|
||||
func TestCmpInt32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := int32(j)
|
||||
return a.CmpInt32(k) == cmpi(i, int64(k))
|
||||
}
|
||||
testBinary(t, "CmpInt32", fun, 64)
|
||||
}
|
||||
|
||||
func TestCmpAbs(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
return a.CmpAbs(NewInt(j)) == cmpi(absi(i), absi(j))
|
||||
}
|
||||
testBinary(t, "CmpAbs", fun, 64)
|
||||
}
|
||||
|
||||
func TestCmpAbsUint32(t *testing.T) {
|
||||
fun := func(i, j int64) bool {
|
||||
a := NewInt(i)
|
||||
k := uint32(j)
|
||||
return a.CmpAbsUint32(k) == cmpi(absi(i), int64(k))
|
||||
}
|
||||
testBinary(t, "CmpAbsUint32", fun, 64)
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
for range perFuncTests {
|
||||
var n = uint32(random.Int63())
|
||||
if NewInt(int64(n)).Uint32() != n {
|
||||
t.Errorf("Uint32 failed for %v", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt32(t *testing.T) {
|
||||
for range perFuncTests {
|
||||
var n = int32(random.Int63())
|
||||
if NewInt(int64(n)).Int32() != n {
|
||||
t.Errorf("Int32 failed for %v", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrt(t *testing.T) {
|
||||
a := NewInt(1)
|
||||
aSquared := NewInt(1)
|
||||
ten := NewInt(10)
|
||||
hundred := NewInt(100)
|
||||
root := new(Int)
|
||||
for range perFuncTests {
|
||||
root := root.Sqrt(aSquared)
|
||||
if root.Cmp(a) != 0 {
|
||||
t.Errorf("Sqrt failed got %d expecting %d", root, a)
|
||||
}
|
||||
a.Mul(a, ten)
|
||||
aSquared.Mul(aSquared, hundred)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lgmp
|
||||
#include <gmp.h>
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const MaxBase = 62
|
||||
|
||||
// itoa is like utoa but it prepends a '-' if neg && x != 0.
|
||||
func itoa(x []byte, neg bool, base int) string {
|
||||
if base < 2 || base > MaxBase {
|
||||
panic("invalid base")
|
||||
}
|
||||
|
||||
// x == 0
|
||||
if len(x) == 0 {
|
||||
return "0"
|
||||
}
|
||||
// len(x) > 0
|
||||
|
||||
n := new(big.Int).SetBytes(x)
|
||||
if neg {
|
||||
n.Neg(n)
|
||||
}
|
||||
return n.Text(base)
|
||||
|
||||
}
|
||||
|
||||
// Text returns the string representation of x in the given base.
|
||||
// Base must be between 2 and 62, inclusive. The result uses the
|
||||
// lower-case letters 'a' to 'z' for digit values 10 to 35, and
|
||||
// the upper-case letters 'A' to 'Z' for digit values 36 to 61.
|
||||
// No prefix (such as "0x") is added to the string. If x is a nil
|
||||
// pointer it returns "<nil>".
|
||||
func (x *Int) Text(base int) string {
|
||||
if x == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
nat := x.Bytes()
|
||||
|
||||
return string(itoa(nat, x.Sign() < 0, base))
|
||||
}
|
||||
|
||||
// Bits return the bits of x
|
||||
func (x *Int) Bits() uint {
|
||||
// return uint(C.mpz_bitcnt(x.i))
|
||||
panic("unimplement")
|
||||
}
|
||||
|
||||
// ToNBytes ouput a bytes to fix n bytes. extend as 0.
|
||||
func toNBytes(b *Int, n int) []byte {
|
||||
abs := b.Bytes()
|
||||
l := len(abs)
|
||||
var s []byte
|
||||
// l==n is the most case (255/256)
|
||||
if l >= n {
|
||||
s = abs[l-n : l]
|
||||
} else {
|
||||
s = make([]byte, n)
|
||||
copy(s[n-l:], abs)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (x *Int) FillBytes(b []byte) []byte {
|
||||
bb := toNBytes(x, len(b))
|
||||
copy(b, bb)
|
||||
return b
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,650 @@
|
||||
// Copyright 2010 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 multi-precision rational numbers.
|
||||
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
/*
|
||||
#include <gmp.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Macros
|
||||
int __mpq_sgn(mpq_ptr op) {
|
||||
return mpq_sgn(op);
|
||||
}
|
||||
int __mpz_cmp_ui(mpz_ptr op, unsigned long n) {
|
||||
return mpz_cmp_ui(op, n);
|
||||
}
|
||||
mpz_ptr _mpq_numref(mpq_t op) {
|
||||
return mpq_numref(op);
|
||||
}
|
||||
mpz_ptr _mpq_denref(mpq_t op) {
|
||||
return mpq_denref(op);
|
||||
}
|
||||
// Sign of the numerator
|
||||
int _mpq_num_sgn(mpq_t op) {
|
||||
return mpz_sgn(mpq_numref(op));
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// A Rat represents a quotient a/b of arbitrary precision.
|
||||
// The zero value for a Rat represents the value 0.
|
||||
type Rat struct {
|
||||
i C.mpq_t
|
||||
init bool
|
||||
}
|
||||
|
||||
// Finalizer - release the memory allocated to the mpz
|
||||
func ratFinalize(z *Rat) {
|
||||
if z.init {
|
||||
runtime.SetFinalizer(z, nil)
|
||||
C.mpq_clear(&z.i[0])
|
||||
z.init = false
|
||||
}
|
||||
}
|
||||
|
||||
// Rat 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 *Rat) doinit() {
|
||||
if z.init {
|
||||
return
|
||||
}
|
||||
z.init = true
|
||||
C.mpq_init(&z.i[0])
|
||||
runtime.SetFinalizer(z, ratFinalize)
|
||||
}
|
||||
|
||||
// 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.Rat
|
||||
func (z *Rat) Clear() {
|
||||
ratFinalize(z)
|
||||
}
|
||||
|
||||
// NewRat creates a new Rat with numerator a and denominator b.
|
||||
func NewRat(a, b int64) *Rat {
|
||||
return new(Rat).SetFrac64(a, b)
|
||||
}
|
||||
|
||||
// SetFloat64 sets z to exactly f and returns z.
|
||||
// If f is not finite, SetFloat returns nil.
|
||||
func (z *Rat) SetFloat64(f float64) *Rat {
|
||||
if math.IsNaN(f) || math.IsInf(f, 0) {
|
||||
return nil
|
||||
}
|
||||
z.doinit()
|
||||
C.mpq_set_d(&z.i[0], C.double(f))
|
||||
return z
|
||||
}
|
||||
|
||||
// Float64Gmp returns the nearest float64 value for z and a bool indicating
|
||||
// whether f represents z exactly. If the magnitude of z is too large to
|
||||
// be represented by a float64, f is an infinity and exact is false.
|
||||
// The sign of f always matches the sign of z, even if f == 0.
|
||||
//
|
||||
// NB This uses GMP which is fast but rounds differently to Float64
|
||||
func (z *Rat) Float64Gmp() (f float64, exact bool) {
|
||||
z.doinit()
|
||||
f = float64(C.mpq_get_d(&z.i[0]))
|
||||
if !(math.IsNaN(f) || math.IsInf(f, 0)) {
|
||||
exact = new(Rat).SetFloat64(f).Cmp(z) == 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// low64 returns the least significant 64 bits of natural number z.
|
||||
func low64(z *Int) uint64 {
|
||||
// FIXME not wildy efficient!
|
||||
t := new(Int).SetUint64(0xffffffffffffffff)
|
||||
t.And(t, z)
|
||||
return t.Uint64()
|
||||
}
|
||||
|
||||
// quotToFloat returns the non-negative IEEE 754 double-precision
|
||||
// value nearest to the quotient a/b, using round-to-even in halfway
|
||||
// cases. It does not mutate its arguments.
|
||||
// Preconditions: b is non-zero; a and b have no common factors.
|
||||
func quotToFloat(a, b *Int) (f float64, exact bool) {
|
||||
// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
|
||||
alen := a.BitLen()
|
||||
if alen == 0 {
|
||||
return 0, true
|
||||
}
|
||||
blen := b.BitLen()
|
||||
if blen == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
|
||||
// 1. Left-shift A or B such that quotient A/B is in [1<<53, 1<<55).
|
||||
// (54 bits if A<B when they are left-aligned, 55 bits if A>=B.)
|
||||
// This is 2 or 3 more than the float64 mantissa field width of 52:
|
||||
// - the optional extra bit is shifted away in step 3 below.
|
||||
// - the high-order 1 is omitted in float64 "normal" representation;
|
||||
// - the low-order 1 will be used during rounding then discarded.
|
||||
exp := alen - blen
|
||||
a2, b2 := new(Int).Set(a), new(Int).Set(b)
|
||||
if shift := 54 - exp; shift > 0 {
|
||||
a2.Lsh(a2, uint(shift))
|
||||
} else if shift < 0 {
|
||||
b2.Lsh(b2, uint(-shift))
|
||||
}
|
||||
|
||||
// 2. Compute quotient and remainder (q, r). NB: due to the
|
||||
// extra shift, the low-order bit of q is logically the
|
||||
// high-order bit of r.
|
||||
q, r := new(Int).DivMod(a2, b2, new(Int)) // (recycle a2)
|
||||
mantissa := low64(q)
|
||||
haveRem := r.Sign() != 0 // mantissa&1 && !haveRem => remainder is exactly half
|
||||
|
||||
// 3. If quotient didn't fit in 54 bits, re-do division by b2<<1
|
||||
// (in effect---we accomplish this incrementally).
|
||||
if mantissa>>54 == 1 {
|
||||
if mantissa&1 == 1 {
|
||||
haveRem = true
|
||||
}
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
if mantissa>>53 != 1 {
|
||||
panic("expected exactly 54 bits of result")
|
||||
}
|
||||
|
||||
// 4. Rounding.
|
||||
if -1022-52 <= exp && exp <= -1022 {
|
||||
// Denormal case; lose 'shift' bits of precision.
|
||||
shift := uint64(-1022 - (exp - 1)) // [1..53)
|
||||
lostbits := mantissa & (1<<shift - 1)
|
||||
haveRem = haveRem || lostbits != 0
|
||||
mantissa >>= shift
|
||||
exp = -1023 + 2
|
||||
}
|
||||
// Round q using round-half-to-even.
|
||||
exact = !haveRem
|
||||
if mantissa&1 != 0 {
|
||||
exact = false
|
||||
if haveRem || mantissa&2 != 0 {
|
||||
if mantissa++; mantissa >= 1<<54 {
|
||||
// Complete rollover 11...1 => 100...0, so shift is safe
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 2^53.
|
||||
|
||||
f = math.Ldexp(float64(mantissa), exp-53)
|
||||
if math.IsInf(f, 0) {
|
||||
exact = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float64 returns the nearest float64 value for z and a bool indicating
|
||||
// whether f represents z exactly. If the magnitude of z is too large to
|
||||
// be represented by a float64, f is an infinity and exact is false.
|
||||
// The sign of f always matches the sign of z, even if f == 0.
|
||||
func (z *Rat) Float64() (f float64, exact bool) {
|
||||
a := z.Num()
|
||||
negative := false
|
||||
if a.Sign() < 0 {
|
||||
a.Neg(a)
|
||||
negative = true
|
||||
}
|
||||
b := z.Denom()
|
||||
f, exact = quotToFloat(a, b)
|
||||
if negative {
|
||||
f = -f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetNum sets the numerator of z returning z
|
||||
//
|
||||
// NB this isn't part of math/big which uses Num().Set() for this
|
||||
// purpose. In gmp Num() returns a copy hence the need for a SetNum()
|
||||
// method.
|
||||
func (z *Rat) SetNum(a *Int) *Rat {
|
||||
z.doinit()
|
||||
a.doinit()
|
||||
C.mpq_set_num(&z.i[0], &a.i[0])
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// SetDenom sets the numerator of z returning z
|
||||
//
|
||||
// NB this isn't part of math/big which uses Num().Set() for this
|
||||
// purpose. In gmp Num() returns a copy hence the need for a SetNum()
|
||||
// method.
|
||||
func (z *Rat) SetDenom(a *Int) *Rat {
|
||||
z.doinit()
|
||||
a.doinit()
|
||||
C.mpq_set_den(&z.i[0], &a.i[0])
|
||||
// If numerator is zero don't canonicalize
|
||||
if C._mpq_num_sgn(&z.i[0]) != 0 {
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// SetFrac sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac(a, b *Int) *Rat {
|
||||
z.doinit()
|
||||
a.doinit()
|
||||
b.doinit()
|
||||
// FIXME copying? or referencing?
|
||||
C.mpq_set_num(&z.i[0], &a.i[0])
|
||||
C.mpq_set_den(&z.i[0], &b.i[0])
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// SetFrac64 sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac64(a, b int64) *Rat {
|
||||
z.doinit()
|
||||
if b == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
// Detect overflow if running on 32 bits
|
||||
if a == int64(C.long(a)) && b == int64(C.long(b)) {
|
||||
if b < 0 {
|
||||
a = -a
|
||||
b = -b
|
||||
}
|
||||
C.mpq_set_si(&z.i[0], C.long(a), C.ulong(b))
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
if b < 0 {
|
||||
// This only happens when b = 1<<63
|
||||
z.Neg(z)
|
||||
}
|
||||
} else {
|
||||
// Slow path but will work on 32 bit architectures
|
||||
z.SetFrac(NewInt(a), NewInt(b))
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) SetInt(x *Int) *Rat {
|
||||
z.doinit()
|
||||
// FIXME copying? or referencing?
|
||||
C.mpq_set_z(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Rat) SetInt64(x int64) *Rat {
|
||||
z.SetFrac64(x, 1)
|
||||
return z
|
||||
}
|
||||
|
||||
// Set sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) Set(x *Rat) *Rat {
|
||||
if z != x {
|
||||
z.doinit()
|
||||
C.mpq_set(&z.i[0], &x.i[0])
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func (z *Rat) Abs(x *Rat) *Rat {
|
||||
z.doinit()
|
||||
C.mpq_abs(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func (z *Rat) Neg(x *Rat) *Rat {
|
||||
z.doinit()
|
||||
C.mpq_neg(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// Inv sets z to 1/x and returns z.
|
||||
func (z *Rat) Inv(x *Rat) *Rat {
|
||||
z.doinit()
|
||||
x.doinit()
|
||||
if x.Sign() == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
C.mpq_inv(&z.i[0], &x.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if z < 0
|
||||
// 0 if z == 0
|
||||
// +1 if z > 0
|
||||
//
|
||||
func (z *Rat) Sign() int {
|
||||
z.doinit()
|
||||
return int(C.__mpq_sgn(&z.i[0]))
|
||||
}
|
||||
|
||||
// IsInt returns true if the denominator of z is 1.
|
||||
func (z *Rat) IsInt() bool {
|
||||
z.doinit()
|
||||
return C.__mpz_cmp_ui(C._mpq_denref(&z.i[0]), C.ulong(1)) == 0
|
||||
}
|
||||
|
||||
// Num returns the numerator of z; it may be <= 0. The result is a
|
||||
// copy of z's numerator; it won't change if a new value is assigned
|
||||
// to z, and vice versa. The sign of the numerator corresponds to the
|
||||
// sign of z.
|
||||
//
|
||||
// NB In math/big this is a reference to the numerator not a copy
|
||||
func (z *Rat) Num() *Int {
|
||||
// Return an initialised *Int so we don't initialize or finalize it by accident
|
||||
z.doinit()
|
||||
res := new(Int)
|
||||
res.doinit()
|
||||
C.mpq_get_num(&res.i[0], &z.i[0])
|
||||
return res
|
||||
}
|
||||
|
||||
// Denom returns the denominator of z; it is always > 0. The result
|
||||
// is a copy of z's denominator; it won't change if a new value is
|
||||
// assigned to z, and vice versa.
|
||||
//
|
||||
// NB In math/big this is a reference to the denominator not a copy
|
||||
func (z *Rat) Denom() *Int {
|
||||
// Return an initialised *Int so we don't initialize or finalize it by accident
|
||||
z.doinit()
|
||||
res := new(Int)
|
||||
res.doinit()
|
||||
C.mpq_get_den(&res.i[0], &z.i[0])
|
||||
return res
|
||||
}
|
||||
|
||||
// Cmp compares z and y and returns:
|
||||
//
|
||||
// -1 if z < y
|
||||
// 0 if z == y
|
||||
// +1 if z > y
|
||||
//
|
||||
func (z *Rat) Cmp(y *Rat) (r int) {
|
||||
z.doinit()
|
||||
y.doinit()
|
||||
r = int(C.mpq_cmp(&z.i[0], &y.i[0]))
|
||||
if r < 0 {
|
||||
r = -1
|
||||
} else if r > 0 {
|
||||
r = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func (z *Rat) Add(x, y *Rat) *Rat {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpq_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 *Rat) Sub(x, y *Rat) *Rat {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpq_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 *Rat) Mul(x, y *Rat) *Rat {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
C.mpq_mul(&z.i[0], &x.i[0], &y.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
// Quo sets z to the quotient x/y and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
func (z *Rat) Quo(x, y *Rat) *Rat {
|
||||
x.doinit()
|
||||
y.doinit()
|
||||
z.doinit()
|
||||
if y.Sign() == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
C.mpq_div(&z.i[0], &x.i[0], &y.i[0])
|
||||
return z
|
||||
}
|
||||
|
||||
func ratTok(ch rune) bool {
|
||||
return strings.IndexRune("+-/0123456789.eE", ch) >= 0
|
||||
}
|
||||
|
||||
// Scan is a support routine for fmt.Scanner. It accepts the formats
|
||||
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
|
||||
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
|
||||
tok, err := s.Token(true, ratTok)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.IndexRune("efgEFGv", ch) < 0 {
|
||||
return errors.New("Rat.Scan: invalid verb")
|
||||
}
|
||||
if _, ok := z.SetString(string(tok)); !ok {
|
||||
return errors.New("Rat.Scan: invalid syntax")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 floating-point number
|
||||
// optionally followed by an exponent. If the operation failed, the value of
|
||||
// z is undefined but the returned value is nil.
|
||||
func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
if len(s) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
z.doinit()
|
||||
a := new(Int)
|
||||
b := new(Int)
|
||||
|
||||
// check for a quotient
|
||||
sep := strings.Index(s, "/")
|
||||
if sep >= 0 {
|
||||
// FIXME Num and Denom are bust
|
||||
// if _, ok := z.Num().SetString(s[0:sep], 10); !ok {
|
||||
// return nil, false
|
||||
// }
|
||||
// if _, ok := z.Denom().SetString(s[sep+1:], 10); !ok {
|
||||
// return nil, false
|
||||
// }
|
||||
if _, ok := a.SetString(s[0:sep], 10); !ok {
|
||||
return nil, false
|
||||
}
|
||||
if _, ok := b.SetString(s[sep+1:], 10); !ok {
|
||||
return nil, false
|
||||
}
|
||||
z.SetFrac(a, b)
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
return z, true
|
||||
}
|
||||
|
||||
// check for a decimal point
|
||||
sep = strings.Index(s, ".")
|
||||
// check for an exponent
|
||||
e := strings.IndexAny(s, "eE")
|
||||
exp := new(Int)
|
||||
if e >= 0 {
|
||||
if e < sep {
|
||||
// The E must come after the decimal point.
|
||||
return nil, false
|
||||
}
|
||||
if _, ok := exp.SetString(s[e+1:], 10); !ok {
|
||||
return nil, 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 := a.SetString(s, 10); !ok {
|
||||
return nil, false
|
||||
}
|
||||
absExp := new(Int).Abs(exp)
|
||||
powTen := new(Int).Exp(_Int10, absExp, nil)
|
||||
if exp.Sign() < 0 {
|
||||
b = powTen
|
||||
} else {
|
||||
a.Mul(a, powTen)
|
||||
b.SetInt64(1)
|
||||
}
|
||||
z.SetFrac(a, b)
|
||||
C.mpq_canonicalize(&z.i[0])
|
||||
|
||||
return z, true
|
||||
}
|
||||
|
||||
// string returns z in the base given
|
||||
func (z *Rat) string(base int) string {
|
||||
if z == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
z.doinit()
|
||||
p := C.mpq_get_str(nil, C.int(base), &z.i[0])
|
||||
s := C.GoString(p)
|
||||
C.free(unsafe.Pointer(p))
|
||||
return s
|
||||
}
|
||||
|
||||
// String returns a string representation of z in the form "a/b" (even if b == 1).
|
||||
func (z *Rat) String() string {
|
||||
s := z.string(10)
|
||||
if !strings.Contains(s, "/") {
|
||||
s += "/1"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return z.string(10)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if z.IsInt() {
|
||||
s := z.string(10)
|
||||
if prec > 0 {
|
||||
s += "." + strings.Repeat("0", prec)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
a := z.Num()
|
||||
a.Abs(a)
|
||||
b := z.Denom()
|
||||
q, r := new(Int).DivMod(a, b, new(Int))
|
||||
|
||||
p := _Int1
|
||||
if prec > 0 {
|
||||
p = new(Int).Exp(_Int10, NewInt(int64(prec)), nil)
|
||||
}
|
||||
|
||||
r.Mul(r, p)
|
||||
r2 := new(Int)
|
||||
r.DivMod(r, b, r2)
|
||||
|
||||
// see if we need to round up
|
||||
r2.Add(r2, r2)
|
||||
if b.Cmp(r2) <= 0 {
|
||||
r.Add(r, _Int1)
|
||||
if r.Cmp(p) >= 0 {
|
||||
q.Add(q, _Int1)
|
||||
r.Sub(r, p)
|
||||
}
|
||||
}
|
||||
|
||||
s := q.string(10)
|
||||
if z.Sign() < 0 {
|
||||
s = "-" + s
|
||||
}
|
||||
|
||||
if prec > 0 {
|
||||
rs := r.string(10)
|
||||
leadingZeros := prec - len(rs)
|
||||
s += "." + strings.Repeat("0", leadingZeros) + rs
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const ratGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (z *Rat) GobEncode() ([]byte, error) {
|
||||
bufa := z.Num().Bytes()
|
||||
bufb := z.Denom().Bytes()
|
||||
buf := make([]byte, 1+4) // extra bytes for version and sign bit (1), and numerator length (4)
|
||||
buf = append(buf, bufa...)
|
||||
buf = append(buf, bufb...)
|
||||
const j = 1 + 4
|
||||
n := len(bufa)
|
||||
if int(uint32(n)) != n {
|
||||
// this should never happen
|
||||
return nil, errors.New("Rat.GobEncode: numerator too large")
|
||||
}
|
||||
binary.BigEndian.PutUint32(buf[1:5], uint32(n))
|
||||
b := ratGobVersion << 1 // make space for sign bit
|
||||
if z.Sign() < 0 {
|
||||
b |= 1
|
||||
}
|
||||
buf[0] = b
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Rat) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
return errors.New("Rat.GobDecode: no data")
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != ratGobVersion {
|
||||
return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
|
||||
}
|
||||
const j = 1 + 4
|
||||
i := j + binary.BigEndian.Uint32(buf[j-4:j])
|
||||
num := new(Int).SetBytes(buf[j:i])
|
||||
den := new(Int).SetBytes(buf[i:])
|
||||
if b&1 != 0 {
|
||||
num.Neg(num)
|
||||
}
|
||||
z.SetFrac(num, den)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,910 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
//go:build gmp
|
||||
// +build gmp
|
||||
|
||||
package gmp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestZeroRat(t *testing.T) {
|
||||
var x, y, z Rat
|
||||
y.SetFrac64(0, 42)
|
||||
|
||||
if x.Cmp(&y) != 0 {
|
||||
t.Errorf("x and y should be both equal and zero")
|
||||
}
|
||||
|
||||
if s := x.String(); s != "0/1" {
|
||||
t.Errorf("got x = %s, want 0/1", s)
|
||||
}
|
||||
|
||||
if s := x.RatString(); s != "0" {
|
||||
t.Errorf("got x = %s, want 0", s)
|
||||
}
|
||||
|
||||
z.Add(&x, &y)
|
||||
if s := z.RatString(); s != "0" {
|
||||
t.Errorf("got x+y = %s, want 0", s)
|
||||
}
|
||||
|
||||
z.Sub(&x, &y)
|
||||
if s := z.RatString(); s != "0" {
|
||||
t.Errorf("got x-y = %s, want 0", s)
|
||||
}
|
||||
|
||||
z.Mul(&x, &y)
|
||||
if s := z.RatString(); s != "0" {
|
||||
t.Errorf("got x*y = %s, want 0", s)
|
||||
}
|
||||
|
||||
// check for division by zero
|
||||
defer func() {
|
||||
if s := recover(); s == nil || s.(string) != "division by zero" {
|
||||
panic(s)
|
||||
}
|
||||
}()
|
||||
z.Quo(&x, &y)
|
||||
}
|
||||
|
||||
var setStringTests = []struct {
|
||||
in, out string
|
||||
ok bool
|
||||
}{
|
||||
{"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 {
|
||||
if !test.ok {
|
||||
t.Errorf("#%d SetString(%q) expected failure", i, test.in)
|
||||
} else if x.RatString() != test.out {
|
||||
t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
|
||||
}
|
||||
} else if x != nil {
|
||||
t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatScan(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
for i, test := range setStringTests {
|
||||
x := new(Rat)
|
||||
buf.Reset()
|
||||
_, _ = buf.WriteString(test.in)
|
||||
|
||||
_, err := fmt.Fscanf(&buf, "%v", x)
|
||||
if err == nil != test.ok {
|
||||
if test.ok {
|
||||
t.Errorf("#%d error: %s", i, err)
|
||||
} else {
|
||||
t.Errorf("#%d expected error", i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil && x.RatString() != test.out {
|
||||
t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var floatStringTests = []struct {
|
||||
in string
|
||||
prec int
|
||||
out string
|
||||
}{
|
||||
{"0", 0, "0"},
|
||||
{"0", 4, "0.0000"},
|
||||
{"1", 0, "1"},
|
||||
{"1", 2, "1.00"},
|
||||
{"-1", 0, "-1"},
|
||||
{".25", 2, "0.25"},
|
||||
{".25", 1, "0.3"},
|
||||
{".25", 3, "0.250"},
|
||||
{"-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) {
|
||||
for i, test := range floatStringTests {
|
||||
x, _ := new(Rat).SetString(test.in)
|
||||
|
||||
if x.FloatString(test.prec) != test.out {
|
||||
t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatSign(t *testing.T) {
|
||||
zero := NewRat(0, 1)
|
||||
for _, a := range setStringTests {
|
||||
x, ok := new(Rat).SetString(a.in)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
s := x.Sign()
|
||||
e := x.Cmp(zero)
|
||||
if s != e {
|
||||
t.Errorf("got %d; want %d for z = %v", s, e, &x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
for i, test := range ratCmpTests {
|
||||
x, _ := new(Rat).SetString(test.rat1)
|
||||
y, _ := new(Rat).SetString(test.rat2)
|
||||
|
||||
out := x.Cmp(y)
|
||||
if out != test.out {
|
||||
t.Errorf("#%d got out = %v; want %v", i, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsInt(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
for _, a := range setStringTests {
|
||||
x, ok := new(Rat).SetString(a.in)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
i := x.IsInt()
|
||||
e := x.Denom().Cmp(one) == 0
|
||||
if i != e {
|
||||
t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatAbs(t *testing.T) {
|
||||
zero := new(Rat)
|
||||
for _, a := range setStringTests {
|
||||
x, ok := new(Rat).SetString(a.in)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
e := new(Rat).Set(x)
|
||||
if e.Cmp(zero) < 0 {
|
||||
e.Sub(zero, e)
|
||||
}
|
||||
z := new(Rat).Abs(x)
|
||||
if z.Cmp(e) != 0 {
|
||||
t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatNeg(t *testing.T) {
|
||||
zero := new(Rat)
|
||||
for _, a := range setStringTests {
|
||||
x, ok := new(Rat).SetString(a.in)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
e := new(Rat).Sub(zero, x)
|
||||
z := new(Rat).Neg(x)
|
||||
if z.Cmp(e) != 0 {
|
||||
t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatInv(t *testing.T) {
|
||||
zero := new(Rat)
|
||||
for _, a := range setStringTests {
|
||||
x, ok := new(Rat).SetString(a.in)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if x.Cmp(zero) == 0 {
|
||||
continue // avoid division by zero
|
||||
}
|
||||
e := new(Rat).SetFrac(x.Denom(), x.Num())
|
||||
z := new(Rat).Inv(x)
|
||||
if z.Cmp(e) != 0 {
|
||||
t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ratBinFun func(z, x, y *Rat) *Rat
|
||||
type ratBinArg struct {
|
||||
x, y, z string
|
||||
}
|
||||
|
||||
func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
|
||||
x, _ := new(Rat).SetString(a.x)
|
||||
y, _ := new(Rat).SetString(a.y)
|
||||
z, _ := new(Rat).SetString(a.z)
|
||||
out := f(new(Rat), x, y)
|
||||
|
||||
if out.Cmp(z) != 0 {
|
||||
t.Errorf("%s #%d got %s want %s", name, i, out, z)
|
||||
}
|
||||
}
|
||||
|
||||
var ratBinTests = []struct {
|
||||
x, y string
|
||||
sum, prod string
|
||||
}{
|
||||
{"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) {
|
||||
for i, test := range ratBinTests {
|
||||
arg := ratBinArg{test.x, test.y, test.sum}
|
||||
testRatBin(t, i, "Add", (*Rat).Add, arg)
|
||||
|
||||
arg = ratBinArg{test.y, test.x, test.sum}
|
||||
testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
|
||||
|
||||
arg = ratBinArg{test.sum, test.x, test.y}
|
||||
testRatBin(t, i, "Sub", (*Rat).Sub, arg)
|
||||
|
||||
arg = ratBinArg{test.sum, test.y, test.x}
|
||||
testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
|
||||
|
||||
arg = ratBinArg{test.x, test.y, test.prod}
|
||||
testRatBin(t, i, "Mul", (*Rat).Mul, arg)
|
||||
|
||||
arg = ratBinArg{test.y, test.x, test.prod}
|
||||
testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
|
||||
|
||||
if test.x != "0" {
|
||||
arg = ratBinArg{test.prod, test.x, test.y}
|
||||
testRatBin(t, i, "Quo", (*Rat).Quo, arg)
|
||||
}
|
||||
|
||||
if test.y != "0" {
|
||||
arg = ratBinArg{test.prod, test.y, test.x}
|
||||
testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue820(t *testing.T) {
|
||||
x := NewRat(3, 1)
|
||||
y := NewRat(2, 1)
|
||||
z := y.Quo(x, y)
|
||||
q := NewRat(3, 2)
|
||||
if z.Cmp(q) != 0 {
|
||||
t.Errorf("got %s want %s", z, q)
|
||||
}
|
||||
|
||||
y = NewRat(3, 1)
|
||||
x = NewRat(2, 1)
|
||||
z = y.Quo(x, y)
|
||||
q = NewRat(2, 3)
|
||||
if z.Cmp(q) != 0 {
|
||||
t.Errorf("got %s want %s", z, q)
|
||||
}
|
||||
|
||||
x = NewRat(3, 1)
|
||||
z = x.Quo(x, x)
|
||||
q = NewRat(3, 3)
|
||||
if z.Cmp(q) != 0 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatGobEncoding(t *testing.T) {
|
||||
var medium bytes.Buffer
|
||||
enc := gob.NewEncoder(&medium)
|
||||
dec := gob.NewDecoder(&medium)
|
||||
for _, test := range encodingTests {
|
||||
medium.Reset() // empty buffer for each test case (in case of failures)
|
||||
var tx Rat
|
||||
tx.SetString(test + ".14159265")
|
||||
if err := enc.Encode(&tx); err != nil {
|
||||
t.Errorf("encoding of %s failed: %s", &tx, err)
|
||||
}
|
||||
var rx Rat
|
||||
if err := dec.Decode(&rx); err != nil {
|
||||
t.Errorf("decoding of %s failed: %s", &tx, err)
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue2379(t *testing.T) {
|
||||
// 1) no aliasing
|
||||
q := NewRat(3, 2)
|
||||
x := new(Rat)
|
||||
x.SetFrac(NewInt(3), NewInt(2))
|
||||
if x.Cmp(q) != 0 {
|
||||
t.Errorf("1) got %s want %s", x, q)
|
||||
}
|
||||
|
||||
// 2) aliasing of numerator
|
||||
x = NewRat(2, 3)
|
||||
x.SetFrac(NewInt(3), x.Num())
|
||||
if x.Cmp(q) != 0 {
|
||||
t.Errorf("2) got %s want %s", x, q)
|
||||
}
|
||||
|
||||
// 3) aliasing of denominator
|
||||
x = NewRat(2, 3)
|
||||
x.SetFrac(x.Denom(), NewInt(2))
|
||||
if x.Cmp(q) != 0 {
|
||||
t.Errorf("3) got %s want %s", x, q)
|
||||
}
|
||||
|
||||
// 4) aliasing of numerator and denominator
|
||||
x = NewRat(2, 3)
|
||||
x.SetFrac(x.Denom(), x.Num())
|
||||
if x.Cmp(q) != 0 {
|
||||
t.Errorf("4) got %s want %s", x, q)
|
||||
}
|
||||
|
||||
// 5) numerator and denominator are the same
|
||||
q = NewRat(1, 1)
|
||||
x = new(Rat)
|
||||
n := NewInt(7)
|
||||
x.SetFrac(n, n)
|
||||
if x.Cmp(q) != 0 {
|
||||
t.Errorf("5) got %s want %s", x, q)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue3521(t *testing.T) {
|
||||
a := new(Int)
|
||||
b := new(Int)
|
||||
a.SetString("64375784358435883458348587", 0)
|
||||
b.SetString("4789759874531", 0)
|
||||
|
||||
// 0) a raw zero value has 1 as denominator
|
||||
zero := new(Rat)
|
||||
one := NewInt(1)
|
||||
if zero.Denom().Cmp(one) != 0 {
|
||||
t.Errorf("0) got %s want %s", zero.Denom(), one)
|
||||
}
|
||||
|
||||
// 1a) a zero value remains zero independent of denominator
|
||||
x := new(Rat)
|
||||
x.SetDenom(new(Int).Neg(b))
|
||||
if x.Cmp(zero) != 0 {
|
||||
t.Errorf("1a) got %s want %s", x, zero)
|
||||
}
|
||||
|
||||
// 1b) a zero value may have a denominator != 0 and != 1
|
||||
x.SetNum(a)
|
||||
qab := new(Rat).SetFrac(a, new(Int).Neg(b)) // FIXME -ve compared to math/big
|
||||
if x.Cmp(qab) != 0 {
|
||||
t.Errorf("1b) got %s want %s", x, qab)
|
||||
}
|
||||
|
||||
// 2a) an integral value becomes a fraction depending on denominator
|
||||
x.SetFrac64(10, 2)
|
||||
x.SetDenom(NewInt(3))
|
||||
q53 := NewRat(5, 3)
|
||||
if x.Cmp(q53) != 0 {
|
||||
t.Errorf("2a) got %s want %s", x, q53)
|
||||
}
|
||||
|
||||
// 2b) an integral value becomes a fraction depending on denominator
|
||||
x = NewRat(10, 2)
|
||||
x.SetDenom(NewInt(3))
|
||||
if x.Cmp(q53) != 0 {
|
||||
t.Errorf("2b) got %s want %s", x, q53)
|
||||
}
|
||||
|
||||
// 3) changing the numerator/denominator of a Rat changes the Rat
|
||||
x.SetFrac(a, b)
|
||||
x.SetNum(NewInt(5))
|
||||
x.SetDenom(NewInt(3))
|
||||
if x.Cmp(q53) != 0 {
|
||||
t.Errorf("3) got %s want %s", x, q53)
|
||||
}
|
||||
}
|
||||
|
||||
// Test inputs to Rat.SetString. The prefix "long:" causes the test
|
||||
// to be skipped in --test.short mode. (The threshold is about 500us.)
|
||||
var float64inputs = []string{
|
||||
// Constants plundered from strconv/testfp.txt.
|
||||
|
||||
// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
|
||||
"5e+125",
|
||||
"69e+267",
|
||||
"999e-026",
|
||||
"7861e-034",
|
||||
"75569e-254",
|
||||
"928609e-261",
|
||||
"9210917e+080",
|
||||
"84863171e+114",
|
||||
"653777767e+273",
|
||||
"5232604057e-298",
|
||||
"27235667517e-109",
|
||||
"653532977297e-123",
|
||||
"3142213164987e-294",
|
||||
"46202199371337e-072",
|
||||
"231010996856685e-073",
|
||||
"9324754620109615e+212",
|
||||
"78459735791271921e+049",
|
||||
"272104041512242479e+200",
|
||||
"6802601037806061975e+198",
|
||||
"20505426358836677347e-221",
|
||||
"836168422905420598437e-234",
|
||||
"4891559871276714924261e+222",
|
||||
|
||||
// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
|
||||
"9e-265",
|
||||
"85e-037",
|
||||
"623e+100",
|
||||
"3571e+263",
|
||||
"81661e+153",
|
||||
"920657e-023",
|
||||
"4603285e-024",
|
||||
"87575437e-309",
|
||||
"245540327e+122",
|
||||
"6138508175e+120",
|
||||
"83356057653e+193",
|
||||
"619534293513e+124",
|
||||
"2335141086879e+218",
|
||||
"36167929443327e-159",
|
||||
"609610927149051e-255",
|
||||
"3743626360493413e-165",
|
||||
"94080055902682397e-242",
|
||||
"899810892172646163e+283",
|
||||
"7120190517612959703e+120",
|
||||
"25188282901709339043e-252",
|
||||
"308984926168550152811e-052",
|
||||
"6372891218502368041059e+064",
|
||||
|
||||
// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
|
||||
"5e-20",
|
||||
"67e+14",
|
||||
"985e+15",
|
||||
"7693e-42",
|
||||
"55895e-16",
|
||||
"996622e-44",
|
||||
"7038531e-32",
|
||||
"60419369e-46",
|
||||
"702990899e-20",
|
||||
"6930161142e-48",
|
||||
"25933168707e+13",
|
||||
"596428896559e+20",
|
||||
|
||||
// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
|
||||
"3e-23",
|
||||
"57e+18",
|
||||
"789e-35",
|
||||
"2539e-18",
|
||||
"76173e+28",
|
||||
"887745e-11",
|
||||
"5382571e-37",
|
||||
"82381273e-35",
|
||||
"750486563e-38",
|
||||
"3752432815e-39",
|
||||
"75224575729e-45",
|
||||
"459926601011e+15",
|
||||
|
||||
// Constants plundered from strconv/atof_test.go.
|
||||
|
||||
"0",
|
||||
"1",
|
||||
"+1",
|
||||
"1e23",
|
||||
"1E23",
|
||||
"100000000000000000000000",
|
||||
"1e-100",
|
||||
"123456700",
|
||||
"99999999999999974834176",
|
||||
"100000000000000000000001",
|
||||
"100000000000000008388608",
|
||||
"100000000000000016777215",
|
||||
"100000000000000016777216",
|
||||
"-1",
|
||||
"-0.1",
|
||||
"-0", // NB: exception made for this input
|
||||
"1e-20",
|
||||
"625e-3",
|
||||
|
||||
// largest float64
|
||||
"1.7976931348623157e308",
|
||||
"-1.7976931348623157e308",
|
||||
// next float64 - too large
|
||||
"1.7976931348623159e308",
|
||||
"-1.7976931348623159e308",
|
||||
// the border is ...158079
|
||||
// borderline - okay
|
||||
"1.7976931348623158e308",
|
||||
"-1.7976931348623158e308",
|
||||
// borderline - too large
|
||||
"1.797693134862315808e308",
|
||||
"-1.797693134862315808e308",
|
||||
|
||||
// a little too large
|
||||
"1e308",
|
||||
"2e308",
|
||||
"1e309",
|
||||
|
||||
// way too large
|
||||
"1e310",
|
||||
"-1e310",
|
||||
"1e400",
|
||||
"-1e400",
|
||||
"long:1e400000",
|
||||
"long:-1e400000",
|
||||
|
||||
// denormalized
|
||||
"1e-305",
|
||||
"1e-306",
|
||||
"1e-307",
|
||||
"1e-308",
|
||||
"1e-309",
|
||||
"1e-310",
|
||||
"1e-322",
|
||||
// smallest denormal
|
||||
"5e-324",
|
||||
"4e-324",
|
||||
"3e-324",
|
||||
// too small
|
||||
"2e-324",
|
||||
// way too small
|
||||
"1e-350",
|
||||
"long:1e-400000",
|
||||
// way too small, negative
|
||||
"-1e-350",
|
||||
"long:-1e-400000",
|
||||
|
||||
// try to overflow exponent
|
||||
// [Disabled: too slow and memory-hungry with rationals.]
|
||||
// "1e-4294967296",
|
||||
// "1e+4294967296",
|
||||
// "1e-18446744073709551616",
|
||||
// "1e+18446744073709551616",
|
||||
|
||||
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
|
||||
"2.2250738585072012e-308",
|
||||
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
|
||||
|
||||
"2.2250738585072011e-308",
|
||||
|
||||
// A very large number (initially wrongly parsed by the fast algorithm).
|
||||
"4.630813248087435e+307",
|
||||
|
||||
// A different kind of very large number.
|
||||
"22.222222222222222",
|
||||
"long:2." + strings.Repeat("2", 4000) + "e+1",
|
||||
|
||||
// Exactly halfway between 1 and math.Nextafter(1, 2).
|
||||
// Round to even (down).
|
||||
"1.00000000000000011102230246251565404236316680908203125",
|
||||
// Slightly lower; still round down.
|
||||
"1.00000000000000011102230246251565404236316680908203124",
|
||||
// Slightly higher; round up.
|
||||
"1.00000000000000011102230246251565404236316680908203126",
|
||||
// Slightly higher, but you have to read all the way to the end.
|
||||
"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
|
||||
|
||||
// Smallest denormal, 2^(-1022-52)
|
||||
"4.940656458412465441765687928682213723651e-324",
|
||||
// Half of smallest denormal, 2^(-1022-53)
|
||||
"2.470328229206232720882843964341106861825e-324",
|
||||
// A little more than the exact half of smallest denormal
|
||||
// 2^-1075 + 2^-1100. (Rounds to 1p-1074.)
|
||||
"2.470328302827751011111470718709768633275e-324",
|
||||
// The exact halfway between smallest normal and largest denormal:
|
||||
// 2^-1022 - 2^-1075. (Rounds to 2^-1022.)
|
||||
"2.225073858507201136057409796709131975935e-308",
|
||||
|
||||
"1152921504606846975", // 1<<60 - 1
|
||||
"-1152921504606846975", // -(1<<60 - 1)
|
||||
"1152921504606846977", // 1<<60 + 1
|
||||
"-1152921504606846977", // -(1<<60 + 1)
|
||||
|
||||
"1/3",
|
||||
}
|
||||
|
||||
// isFinite reports whether f represents a finite rational value.
|
||||
// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
|
||||
func isFinite(f float64) bool {
|
||||
return math.Abs(f) <= math.MaxFloat64
|
||||
}
|
||||
|
||||
func TestFloat64SpecialCases(t *testing.T) {
|
||||
for _, input := range float64inputs {
|
||||
if strings.HasPrefix(input, "long:") {
|
||||
if testing.Short() {
|
||||
continue
|
||||
}
|
||||
input = input[len("long:"):]
|
||||
}
|
||||
|
||||
r, ok := new(Rat).SetString(input)
|
||||
if !ok {
|
||||
t.Errorf("Rat.SetString(%q) failed", input)
|
||||
continue
|
||||
}
|
||||
f, exact := r.Float64()
|
||||
|
||||
// 1. Check string -> Rat -> float64 conversions are
|
||||
// consistent with strconv.ParseFloat.
|
||||
// Skip this check if the input uses "a/b" rational syntax.
|
||||
if !strings.Contains(input, "/") {
|
||||
e, _ := strconv.ParseFloat(input, 64)
|
||||
|
||||
// Careful: negative Rats too small for
|
||||
// float64 become -0, but Rat obviously cannot
|
||||
// preserve the sign from SetString("-0").
|
||||
switch {
|
||||
case math.Float64bits(e) == math.Float64bits(f):
|
||||
// Ok: bitwise equal.
|
||||
case f == 0 && r.Num().BitLen() == 0:
|
||||
// Ok: Rat(0) is equivalent to both +/- float64(0).
|
||||
default:
|
||||
t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
|
||||
}
|
||||
}
|
||||
|
||||
if !isFinite(f) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 2. Check f is best approximation to r.
|
||||
if !checkIsBestApprox(t, f, r) {
|
||||
// Append context information.
|
||||
t.Errorf("(input was %q)", input)
|
||||
}
|
||||
|
||||
// 3. Check f->R->f roundtrip is non-lossy.
|
||||
checkNonLossyRoundtrip(t, f)
|
||||
|
||||
// 4. Check exactness using slow algorithm.
|
||||
if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
|
||||
t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64Distribution(t *testing.T) {
|
||||
// Generate a distribution of (sign, mantissa, exp) values
|
||||
// broader than the float64 range, and check Rat.Float64()
|
||||
// always picks the closest float64 approximation.
|
||||
var add = []int64{
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
9,
|
||||
11,
|
||||
}
|
||||
var winc, einc = uint64(1), int(1) // soak test (~75s on x86-64)
|
||||
if testing.Short() {
|
||||
winc, einc = 10, 500 // quick test (~12ms on x86-64)
|
||||
}
|
||||
|
||||
for _, sign := range "+-" {
|
||||
for _, a := range add {
|
||||
for wid := uint64(0); wid < 60; wid += winc {
|
||||
b := int64(1<<wid + a)
|
||||
if sign == '-' {
|
||||
b = -b
|
||||
}
|
||||
for exp := -1100; exp < 1100; exp += einc {
|
||||
num, den := NewInt(b), NewInt(1)
|
||||
if exp > 0 {
|
||||
num.Lsh(num, uint(exp))
|
||||
} else {
|
||||
den.Lsh(den, uint(-exp))
|
||||
}
|
||||
r := new(Rat).SetFrac(num, den)
|
||||
f, _ := r.Float64()
|
||||
|
||||
if !checkIsBestApprox(t, f, r) {
|
||||
// Append context information.
|
||||
t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
|
||||
b, exp, f, f, math.Ldexp(float64(b), exp), r)
|
||||
}
|
||||
|
||||
checkNonLossyRoundtrip(t, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestFloat64NonFinite checks that SetFloat64 of a non-finite value
|
||||
// returns nil.
|
||||
func TestSetFloat64NonFinite(t *testing.T) {
|
||||
for _, f := range []float64{math.NaN(), math.Inf(+1), math.Inf(-1)} {
|
||||
var r Rat
|
||||
if r2 := r.SetFloat64(f); r2 != nil {
|
||||
t.Errorf("SetFloat64(%g) was %v, want nil", f, r2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkNonLossyRoundtrip checks that a float->Rat->float roundtrip is
|
||||
// non-lossy for finite f.
|
||||
func checkNonLossyRoundtrip(t *testing.T, f float64) {
|
||||
if !isFinite(f) {
|
||||
return
|
||||
}
|
||||
r := new(Rat).SetFloat64(f)
|
||||
if r == nil {
|
||||
t.Errorf("Rat.SetFloat64(%g (%b)) == nil", f, f)
|
||||
return
|
||||
}
|
||||
f2, exact := r.Float64()
|
||||
if f != f2 || !exact {
|
||||
t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta = %b",
|
||||
f, f2, f2, exact, f, f, true, f2-f)
|
||||
}
|
||||
}
|
||||
|
||||
// delta returns the absolute difference between r and f.
|
||||
func delta(r *Rat, f float64) *Rat {
|
||||
d := new(Rat).Sub(r, new(Rat).SetFloat64(f))
|
||||
return d.Abs(d)
|
||||
}
|
||||
|
||||
// checkIsBestApprox checks that f is the best possible float64
|
||||
// approximation of r.
|
||||
// Returns true on success.
|
||||
func checkIsBestApprox(t *testing.T, f float64, r *Rat) bool {
|
||||
if math.Abs(f) >= math.MaxFloat64 {
|
||||
// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat64).
|
||||
// But we have tests for these special cases.
|
||||
return true
|
||||
}
|
||||
|
||||
// r must be strictly between f0 and f1, the floats bracketing f.
|
||||
f0 := math.Nextafter(f, math.Inf(-1))
|
||||
f1 := math.Nextafter(f, math.Inf(+1))
|
||||
|
||||
// For f to be correct, r must be closer to f than to f0 or f1.
|
||||
df := delta(r, f)
|
||||
df0 := delta(r, f0)
|
||||
df1 := delta(r, f1)
|
||||
if df.Cmp(df0) > 0 {
|
||||
t.Errorf("Rat(%v).Float64() = %g (%b), but previous float64 %g (%b) is closer", r, f, f, f0, f0)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df1) > 0 {
|
||||
t.Errorf("Rat(%v).Float64() = %g (%b), but next float64 %g (%b) is closer", r, f, f, f1, f1)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df0) == 0 && !isEven(f) {
|
||||
t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df1) == 0 && !isEven(f) {
|
||||
t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isEven(f float64) bool { return math.Float64bits(f)&1 == 0 }
|
||||
|
||||
func TestIsFinite(t *testing.T) {
|
||||
finites := []float64{
|
||||
1.0 / 3,
|
||||
4891559871276714924261e+222,
|
||||
math.MaxFloat64,
|
||||
math.SmallestNonzeroFloat64,
|
||||
-math.MaxFloat64,
|
||||
-math.SmallestNonzeroFloat64,
|
||||
}
|
||||
for _, f := range finites {
|
||||
if !isFinite(f) {
|
||||
t.Errorf("!IsFinite(%g (%b))", f, f)
|
||||
}
|
||||
}
|
||||
nonfinites := []float64{
|
||||
math.NaN(),
|
||||
math.Inf(-1),
|
||||
math.Inf(+1),
|
||||
}
|
||||
for _, f := range nonfinites {
|
||||
if isFinite(f) {
|
||||
t.Errorf("IsFinite(%g, (%b))", f, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user