mirror of https://github.com/golang/go.git
cmd/internal/gc/big: vendored math/big for use by gc
This is vendored copy of the pure-Go version of math/big. To update, run vendor.bash in place. This will permit the use of the new big.Float functionality in gc (which is not available in 1.4, the version used for bootstrapping). Change-Id: I4dcdea875d54710005ca3fdea2e0e30422b1b46d Reviewed-on: https://go-review.googlesource.com/7857 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
a1bb3030c8
commit
e5a0d6399e
|
|
@ -0,0 +1,16 @@
|
|||
// generated by stringer -type=Accuracy; DO NOT EDIT
|
||||
|
||||
package big
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _Accuracy_name = "ExactBelowAboveUndef"
|
||||
|
||||
var _Accuracy_index = [...]uint8{0, 5, 10, 15, 20}
|
||||
|
||||
func (i Accuracy) String() string {
|
||||
if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
|
||||
return fmt.Sprintf("Accuracy(%d)", i)
|
||||
}
|
||||
return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
|
||||
}
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
// 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 provides Go implementations of elementary multi-precision
|
||||
// arithmetic operations on word vectors. Needed for platforms without
|
||||
// assembly implementations of these routines.
|
||||
|
||||
package big
|
||||
|
||||
// A Word represents a single digit of a multi-precision unsigned integer.
|
||||
type Word uintptr
|
||||
|
||||
const (
|
||||
// Compute the size _S of a Word in bytes.
|
||||
_m = ^Word(0)
|
||||
_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
|
||||
_S = 1 << _logS
|
||||
|
||||
_W = _S << 3 // word size in bits
|
||||
_B = 1 << _W // digit base
|
||||
_M = _B - 1 // digit mask
|
||||
|
||||
_W2 = _W / 2 // half word size in bits
|
||||
_B2 = 1 << _W2 // half digit base
|
||||
_M2 = _B2 - 1 // half digit mask
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Elementary operations on words
|
||||
//
|
||||
// These operations are used by the vector operations below.
|
||||
|
||||
// z1<<_W + z0 = x+y+c, with c == 0 or 1
|
||||
func addWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
yc := y + c
|
||||
z0 = x + yc
|
||||
if z0 < x || yc < y {
|
||||
z1 = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x-y-c, with c == 0 or 1
|
||||
func subWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
yc := y + c
|
||||
z0 = x - yc
|
||||
if z0 > x || yc < y {
|
||||
z1 = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x*y
|
||||
// Adapted from Warren, Hacker's Delight, p. 132.
|
||||
func mulWW_g(x, y Word) (z1, z0 Word) {
|
||||
x0 := x & _M2
|
||||
x1 := x >> _W2
|
||||
y0 := y & _M2
|
||||
y1 := y >> _W2
|
||||
w0 := x0 * y0
|
||||
t := x1*y0 + w0>>_W2
|
||||
w1 := t & _M2
|
||||
w2 := t >> _W2
|
||||
w1 += x0 * y1
|
||||
z1 = x1*y1 + w2 + w1>>_W2
|
||||
z0 = x * y
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x*y + c
|
||||
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
z1, zz0 := mulWW_g(x, y)
|
||||
if z0 = zz0 + c; z0 < zz0 {
|
||||
z1++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Length of x in bits.
|
||||
func bitLen_g(x Word) (n int) {
|
||||
for ; x >= 0x8000; x >>= 16 {
|
||||
n += 16
|
||||
}
|
||||
if x >= 0x80 {
|
||||
x >>= 8
|
||||
n += 8
|
||||
}
|
||||
if x >= 0x8 {
|
||||
x >>= 4
|
||||
n += 4
|
||||
}
|
||||
if x >= 0x2 {
|
||||
x >>= 2
|
||||
n += 2
|
||||
}
|
||||
if x >= 0x1 {
|
||||
n++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// log2 computes the integer binary logarithm of x.
|
||||
// The result is the integer n for which 2^n <= x < 2^(n+1).
|
||||
// If x == 0, the result is -1.
|
||||
func log2(x Word) int {
|
||||
return bitLen(x) - 1
|
||||
}
|
||||
|
||||
// Number of leading zeros in x.
|
||||
func leadingZeros(x Word) uint {
|
||||
return uint(_W - bitLen(x))
|
||||
}
|
||||
|
||||
// q = (u1<<_W + u0 - r)/y
|
||||
// Adapted from Warren, Hacker's Delight, p. 152.
|
||||
func divWW_g(u1, u0, v Word) (q, r Word) {
|
||||
if u1 >= v {
|
||||
return 1<<_W - 1, 1<<_W - 1
|
||||
}
|
||||
|
||||
s := leadingZeros(v)
|
||||
v <<= s
|
||||
|
||||
vn1 := v >> _W2
|
||||
vn0 := v & _M2
|
||||
un32 := u1<<s | u0>>(_W-s)
|
||||
un10 := u0 << s
|
||||
un1 := un10 >> _W2
|
||||
un0 := un10 & _M2
|
||||
q1 := un32 / vn1
|
||||
rhat := un32 - q1*vn1
|
||||
|
||||
for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
|
||||
q1--
|
||||
rhat += vn1
|
||||
if rhat >= _B2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
un21 := un32*_B2 + un1 - q1*v
|
||||
q0 := un21 / vn1
|
||||
rhat = un21 - q0*vn1
|
||||
|
||||
for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
|
||||
q0--
|
||||
rhat += vn1
|
||||
if rhat >= _B2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
|
||||
}
|
||||
|
||||
// Keep for performance debugging.
|
||||
// Using addWW_g is likely slower.
|
||||
const use_addWW_g = false
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi + yi + c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func subVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi - yi - c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Argument y must be either 0 or 1.
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], c, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi + c
|
||||
z[i] = zi
|
||||
c = xi &^ zi >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], c, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi - c
|
||||
z[i] = zi
|
||||
c = (zi &^ xi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shlVU_g(z, x []Word, s uint) (c Word) {
|
||||
if n := len(z); n > 0 {
|
||||
ŝ := _W - s
|
||||
w1 := x[n-1]
|
||||
c = w1 >> ŝ
|
||||
for i := n - 1; i > 0; i-- {
|
||||
w := w1
|
||||
w1 = x[i-1]
|
||||
z[i] = w<<s | w1>>ŝ
|
||||
}
|
||||
z[0] = w1 << s
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shrVU_g(z, x []Word, s uint) (c Word) {
|
||||
if n := len(z); n > 0 {
|
||||
ŝ := _W - s
|
||||
w1 := x[0]
|
||||
c = w1 << ŝ
|
||||
for i := 0; i < n-1; i++ {
|
||||
w := w1
|
||||
w1 = x[i+1]
|
||||
z[i] = w>>s | w1<<ŝ
|
||||
}
|
||||
z[n-1] = w1 >> s
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
|
||||
c = r
|
||||
for i := range z {
|
||||
c, z[i] = mulAddWWW_g(x[i], y, c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
|
||||
func addMulVVW_g(z, x []Word, y Word) (c Word) {
|
||||
for i := range z {
|
||||
z1, z0 := mulAddWWW_g(x[i], y, z[i])
|
||||
c, z[i] = addWW_g(z0, c, 0)
|
||||
c += z1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
|
||||
r = xn
|
||||
for i := len(z) - 1; i >= 0; i-- {
|
||||
z[i], r = divWW_g(r, x[i], y)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
func mulWW(x, y Word) (z1, z0 Word) {
|
||||
return mulWW_g(x, y)
|
||||
}
|
||||
|
||||
func divWW(x1, x0, y Word) (q, r Word) {
|
||||
return divWW_g(x1, x0, y)
|
||||
}
|
||||
|
||||
func addVV(z, x, y []Word) (c Word) {
|
||||
return addVV_g(z, x, y)
|
||||
}
|
||||
|
||||
func subVV(z, x, y []Word) (c Word) {
|
||||
return subVV_g(z, x, y)
|
||||
}
|
||||
|
||||
func addVW(z, x []Word, y Word) (c Word) {
|
||||
return addVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func subVW(z, x []Word, y Word) (c Word) {
|
||||
return subVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func shlVU(z, x []Word, s uint) (c Word) {
|
||||
return shlVU_g(z, x, s)
|
||||
}
|
||||
|
||||
func shrVU(z, x []Word, s uint) (c Word) {
|
||||
return shrVU_g(z, x, s)
|
||||
}
|
||||
|
||||
func mulAddVWW(z, x []Word, y, r Word) (c Word) {
|
||||
return mulAddVWW_g(z, x, y, r)
|
||||
}
|
||||
|
||||
func addMulVVW(z, x []Word, y Word) (c Word) {
|
||||
return addMulVVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
|
||||
return divWVW_g(z, xn, x, y)
|
||||
}
|
||||
|
||||
func bitLen(x Word) (n int) {
|
||||
return bitLen_g(x)
|
||||
}
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
// 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 big
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type funWW func(x, y, c Word) (z1, z0 Word)
|
||||
type argWW struct {
|
||||
x, y, c, z1, z0 Word
|
||||
}
|
||||
|
||||
var sumWW = []argWW{
|
||||
{0, 0, 0, 0, 0},
|
||||
{0, 1, 0, 0, 1},
|
||||
{0, 0, 1, 0, 1},
|
||||
{0, 1, 1, 0, 2},
|
||||
{12345, 67890, 0, 0, 80235},
|
||||
{12345, 67890, 1, 0, 80236},
|
||||
{_M, 1, 0, 1, 0},
|
||||
{_M, 0, 1, 1, 0},
|
||||
{_M, 1, 1, 1, 1},
|
||||
{_M, _M, 0, 1, _M - 1},
|
||||
{_M, _M, 1, 1, _M},
|
||||
}
|
||||
|
||||
func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
|
||||
z1, z0 := f(a.x, a.y, a.c)
|
||||
if z1 != a.z1 || z0 != a.z0 {
|
||||
t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunWW(t *testing.T) {
|
||||
for _, a := range sumWW {
|
||||
arg := a
|
||||
testFunWW(t, "addWW_g", addWW_g, arg)
|
||||
|
||||
arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
|
||||
testFunWW(t, "addWW_g symmetric", addWW_g, arg)
|
||||
|
||||
arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
|
||||
testFunWW(t, "subWW_g", subWW_g, arg)
|
||||
|
||||
arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
|
||||
testFunWW(t, "subWW_g symmetric", subWW_g, arg)
|
||||
}
|
||||
}
|
||||
|
||||
type funVV func(z, x, y []Word) (c Word)
|
||||
type argVV struct {
|
||||
z, x, y nat
|
||||
c Word
|
||||
}
|
||||
|
||||
var sumVV = []argVV{
|
||||
{},
|
||||
{nat{0}, nat{0}, nat{0}, 0},
|
||||
{nat{1}, nat{1}, nat{0}, 0},
|
||||
{nat{0}, nat{_M}, nat{1}, 1},
|
||||
{nat{80235}, nat{12345}, nat{67890}, 0},
|
||||
{nat{_M - 1}, nat{_M}, nat{_M}, 1},
|
||||
{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
|
||||
{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
|
||||
{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
|
||||
}
|
||||
|
||||
func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
|
||||
z := make(nat, len(a.z))
|
||||
c := f(z, a.x, a.y)
|
||||
for i, zi := range z {
|
||||
if zi != a.z[i] {
|
||||
t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
if c != a.c {
|
||||
t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunVV(t *testing.T) {
|
||||
for _, a := range sumVV {
|
||||
arg := a
|
||||
testFunVV(t, "addVV_g", addVV_g, arg)
|
||||
testFunVV(t, "addVV", addVV, arg)
|
||||
|
||||
arg = argVV{a.z, a.y, a.x, a.c}
|
||||
testFunVV(t, "addVV_g symmetric", addVV_g, arg)
|
||||
testFunVV(t, "addVV symmetric", addVV, arg)
|
||||
|
||||
arg = argVV{a.x, a.z, a.y, a.c}
|
||||
testFunVV(t, "subVV_g", subVV_g, arg)
|
||||
testFunVV(t, "subVV", subVV, arg)
|
||||
|
||||
arg = argVV{a.y, a.z, a.x, a.c}
|
||||
testFunVV(t, "subVV_g symmetric", subVV_g, arg)
|
||||
testFunVV(t, "subVV symmetric", subVV, arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Always the same seed for reproducible results.
|
||||
var rnd = rand.New(rand.NewSource(0))
|
||||
|
||||
func rndW() Word {
|
||||
return Word(rnd.Int63()<<1 | rnd.Int63n(2))
|
||||
}
|
||||
|
||||
func rndV(n int) []Word {
|
||||
v := make([]Word, n)
|
||||
for i := range v {
|
||||
v[i] = rndW()
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func benchmarkFunVV(b *testing.B, f funVV, n int) {
|
||||
x := rndV(n)
|
||||
y := rndV(n)
|
||||
z := make([]Word, n)
|
||||
b.SetBytes(int64(n * _W))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f(z, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddVV_1(b *testing.B) { benchmarkFunVV(b, addVV, 1) }
|
||||
func BenchmarkAddVV_2(b *testing.B) { benchmarkFunVV(b, addVV, 2) }
|
||||
func BenchmarkAddVV_3(b *testing.B) { benchmarkFunVV(b, addVV, 3) }
|
||||
func BenchmarkAddVV_4(b *testing.B) { benchmarkFunVV(b, addVV, 4) }
|
||||
func BenchmarkAddVV_5(b *testing.B) { benchmarkFunVV(b, addVV, 5) }
|
||||
func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) }
|
||||
func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) }
|
||||
func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) }
|
||||
func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) }
|
||||
func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) }
|
||||
|
||||
type funVW func(z, x []Word, y Word) (c Word)
|
||||
type argVW struct {
|
||||
z, x nat
|
||||
y Word
|
||||
c Word
|
||||
}
|
||||
|
||||
var sumVW = []argVW{
|
||||
{},
|
||||
{nil, nil, 2, 2},
|
||||
{nat{0}, nat{0}, 0, 0},
|
||||
{nat{1}, nat{0}, 1, 0},
|
||||
{nat{1}, nat{1}, 0, 0},
|
||||
{nat{0}, nat{_M}, 1, 1},
|
||||
{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
|
||||
}
|
||||
|
||||
var prodVW = []argVW{
|
||||
{},
|
||||
{nat{0}, nat{0}, 0, 0},
|
||||
{nat{0}, nat{_M}, 0, 0},
|
||||
{nat{0}, nat{0}, _M, 0},
|
||||
{nat{1}, nat{1}, 1, 0},
|
||||
{nat{22793}, nat{991}, 23, 0},
|
||||
{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
|
||||
{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
|
||||
{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
|
||||
{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
|
||||
{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
|
||||
{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
|
||||
}
|
||||
|
||||
var lshVW = []argVW{
|
||||
{},
|
||||
{nat{0}, nat{0}, 0, 0},
|
||||
{nat{0}, nat{0}, 1, 0},
|
||||
{nat{0}, nat{0}, 20, 0},
|
||||
|
||||
{nat{_M}, nat{_M}, 0, 0},
|
||||
{nat{_M << 1 & _M}, nat{_M}, 1, 1},
|
||||
{nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
|
||||
|
||||
{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
|
||||
{nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
|
||||
{nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
|
||||
}
|
||||
|
||||
var rshVW = []argVW{
|
||||
{},
|
||||
{nat{0}, nat{0}, 0, 0},
|
||||
{nat{0}, nat{0}, 1, 0},
|
||||
{nat{0}, nat{0}, 20, 0},
|
||||
|
||||
{nat{_M}, nat{_M}, 0, 0},
|
||||
{nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
|
||||
{nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
|
||||
|
||||
{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
|
||||
{nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
|
||||
{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
|
||||
}
|
||||
|
||||
func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
|
||||
z := make(nat, len(a.z))
|
||||
c := f(z, a.x, a.y)
|
||||
for i, zi := range z {
|
||||
if zi != a.z[i] {
|
||||
t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
if c != a.c {
|
||||
t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
|
||||
}
|
||||
}
|
||||
|
||||
func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
|
||||
return func(z, x []Word, s Word) (c Word) {
|
||||
return f(z, x, uint(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunVW(t *testing.T) {
|
||||
for _, a := range sumVW {
|
||||
arg := a
|
||||
testFunVW(t, "addVW_g", addVW_g, arg)
|
||||
testFunVW(t, "addVW", addVW, arg)
|
||||
|
||||
arg = argVW{a.x, a.z, a.y, a.c}
|
||||
testFunVW(t, "subVW_g", subVW_g, arg)
|
||||
testFunVW(t, "subVW", subVW, arg)
|
||||
}
|
||||
|
||||
shlVW_g := makeFunVW(shlVU_g)
|
||||
shlVW := makeFunVW(shlVU)
|
||||
for _, a := range lshVW {
|
||||
arg := a
|
||||
testFunVW(t, "shlVU_g", shlVW_g, arg)
|
||||
testFunVW(t, "shlVU", shlVW, arg)
|
||||
}
|
||||
|
||||
shrVW_g := makeFunVW(shrVU_g)
|
||||
shrVW := makeFunVW(shrVU)
|
||||
for _, a := range rshVW {
|
||||
arg := a
|
||||
testFunVW(t, "shrVU_g", shrVW_g, arg)
|
||||
testFunVW(t, "shrVU", shrVW, arg)
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkFunVW(b *testing.B, f funVW, n int) {
|
||||
x := rndV(n)
|
||||
y := rndW()
|
||||
z := make([]Word, n)
|
||||
b.SetBytes(int64(n * _S))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f(z, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddVW_1(b *testing.B) { benchmarkFunVW(b, addVW, 1) }
|
||||
func BenchmarkAddVW_2(b *testing.B) { benchmarkFunVW(b, addVW, 2) }
|
||||
func BenchmarkAddVW_3(b *testing.B) { benchmarkFunVW(b, addVW, 3) }
|
||||
func BenchmarkAddVW_4(b *testing.B) { benchmarkFunVW(b, addVW, 4) }
|
||||
func BenchmarkAddVW_5(b *testing.B) { benchmarkFunVW(b, addVW, 5) }
|
||||
func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) }
|
||||
func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) }
|
||||
func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) }
|
||||
func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) }
|
||||
func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) }
|
||||
|
||||
type funVWW func(z, x []Word, y, r Word) (c Word)
|
||||
type argVWW struct {
|
||||
z, x nat
|
||||
y, r Word
|
||||
c Word
|
||||
}
|
||||
|
||||
var prodVWW = []argVWW{
|
||||
{},
|
||||
{nat{0}, nat{0}, 0, 0, 0},
|
||||
{nat{991}, nat{0}, 0, 991, 0},
|
||||
{nat{0}, nat{_M}, 0, 0, 0},
|
||||
{nat{991}, nat{_M}, 0, 991, 0},
|
||||
{nat{0}, nat{0}, _M, 0, 0},
|
||||
{nat{991}, nat{0}, _M, 991, 0},
|
||||
{nat{1}, nat{1}, 1, 0, 0},
|
||||
{nat{992}, nat{1}, 1, 991, 0},
|
||||
{nat{22793}, nat{991}, 23, 0, 0},
|
||||
{nat{22800}, nat{991}, 23, 7, 0},
|
||||
{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
|
||||
{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
|
||||
{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
|
||||
{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
|
||||
{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
|
||||
{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
|
||||
{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
|
||||
{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
|
||||
{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
|
||||
{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
|
||||
{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
|
||||
{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
|
||||
}
|
||||
|
||||
func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
|
||||
z := make(nat, len(a.z))
|
||||
c := f(z, a.x, a.y, a.r)
|
||||
for i, zi := range z {
|
||||
if zi != a.z[i] {
|
||||
t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
if c != a.c {
|
||||
t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gri) mulAddVWW and divWVW are symmetric operations but
|
||||
// their signature is not symmetric. Try to unify.
|
||||
|
||||
type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
|
||||
type argWVW struct {
|
||||
z nat
|
||||
xn Word
|
||||
x nat
|
||||
y Word
|
||||
r Word
|
||||
}
|
||||
|
||||
func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
|
||||
z := make(nat, len(a.z))
|
||||
r := f(z, a.xn, a.x, a.y)
|
||||
for i, zi := range z {
|
||||
if zi != a.z[i] {
|
||||
t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
if r != a.r {
|
||||
t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunVWW(t *testing.T) {
|
||||
for _, a := range prodVWW {
|
||||
arg := a
|
||||
testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
|
||||
testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
|
||||
|
||||
if a.y != 0 && a.r < a.y {
|
||||
arg := argWVW{a.x, a.c, a.z, a.y, a.r}
|
||||
testFunWVW(t, "divWVW_g", divWVW_g, arg)
|
||||
testFunWVW(t, "divWVW", divWVW, arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mulWWTests = []struct {
|
||||
x, y Word
|
||||
q, r Word
|
||||
}{
|
||||
{_M, _M, _M - 1, 1},
|
||||
// 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
|
||||
}
|
||||
|
||||
func TestMulWW(t *testing.T) {
|
||||
for i, test := range mulWWTests {
|
||||
q, r := mulWW_g(test.x, test.y)
|
||||
if q != test.q || r != test.r {
|
||||
t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mulAddWWWTests = []struct {
|
||||
x, y, c Word
|
||||
q, r Word
|
||||
}{
|
||||
// TODO(agl): These will only work on 64-bit platforms.
|
||||
// {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
|
||||
// {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
|
||||
{_M, _M, 0, _M - 1, 1},
|
||||
{_M, _M, _M, _M, 0},
|
||||
}
|
||||
|
||||
func TestMulAddWWW(t *testing.T) {
|
||||
for i, test := range mulAddWWWTests {
|
||||
q, r := mulAddWWW_g(test.x, test.y, test.c)
|
||||
if q != test.q || r != test.r {
|
||||
t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkAddMulVVW(b *testing.B, n int) {
|
||||
x := rndV(n)
|
||||
y := rndW()
|
||||
z := make([]Word, n)
|
||||
b.SetBytes(int64(n * _W))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
addMulVVW(z, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddMulVVW_1(b *testing.B) { benchmarkAddMulVVW(b, 1) }
|
||||
func BenchmarkAddMulVVW_2(b *testing.B) { benchmarkAddMulVVW(b, 2) }
|
||||
func BenchmarkAddMulVVW_3(b *testing.B) { benchmarkAddMulVVW(b, 3) }
|
||||
func BenchmarkAddMulVVW_4(b *testing.B) { benchmarkAddMulVVW(b, 4) }
|
||||
func BenchmarkAddMulVVW_5(b *testing.B) { benchmarkAddMulVVW(b, 5) }
|
||||
func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) }
|
||||
func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) }
|
||||
func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) }
|
||||
func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) }
|
||||
func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) }
|
||||
|
||||
func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
|
||||
for i := 0; i <= _W; i++ {
|
||||
x := Word(1) << uint(i-1) // i == 0 => x == 0
|
||||
n := f(x)
|
||||
if n != i {
|
||||
t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWordBitLen(t *testing.T) {
|
||||
testWordBitLen(t, "bitLen", bitLen)
|
||||
testWordBitLen(t, "bitLen_g", bitLen_g)
|
||||
}
|
||||
|
||||
// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
|
||||
func benchmarkBitLenN(b *testing.B, nbits uint) {
|
||||
testword := Word((uint64(1) << nbits) - 1)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bitLen(testword)
|
||||
}
|
||||
}
|
||||
|
||||
// Individual bitLen tests. Numbers chosen to examine both sides
|
||||
// of powers-of-two boundaries.
|
||||
func BenchmarkBitLen0(b *testing.B) { benchmarkBitLenN(b, 0) }
|
||||
func BenchmarkBitLen1(b *testing.B) { benchmarkBitLenN(b, 1) }
|
||||
func BenchmarkBitLen2(b *testing.B) { benchmarkBitLenN(b, 2) }
|
||||
func BenchmarkBitLen3(b *testing.B) { benchmarkBitLenN(b, 3) }
|
||||
func BenchmarkBitLen4(b *testing.B) { benchmarkBitLenN(b, 4) }
|
||||
func BenchmarkBitLen5(b *testing.B) { benchmarkBitLenN(b, 5) }
|
||||
func BenchmarkBitLen8(b *testing.B) { benchmarkBitLenN(b, 8) }
|
||||
func BenchmarkBitLen9(b *testing.B) { benchmarkBitLenN(b, 9) }
|
||||
func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
|
||||
func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
|
||||
func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2015 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 the Bits type used for testing Float operations
|
||||
// via an independent (albeit slower) representations for floating-point
|
||||
// numbers.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A Bits value b represents a finite floating-point number x of the form
|
||||
//
|
||||
// x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
|
||||
//
|
||||
// The order of slice elements is not significant. Negative elements may be
|
||||
// used to form fractions. A Bits value is normalized if each b[i] occurs at
|
||||
// most once. For instance Bits{0, 0, 1} is not normalized but represents the
|
||||
// same floating-point number as Bits{2}, which is normalized. The zero (nil)
|
||||
// value of Bits is a ready to use Bits value and represents the value 0.
|
||||
type Bits []int
|
||||
|
||||
func (x Bits) add(y Bits) Bits {
|
||||
return append(x, y...)
|
||||
}
|
||||
|
||||
func (x Bits) mul(y Bits) Bits {
|
||||
var p Bits
|
||||
for _, x := range x {
|
||||
for _, y := range y {
|
||||
p = append(p, x+y)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func TestMulBits(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x, y, want Bits
|
||||
}{
|
||||
{nil, nil, nil},
|
||||
{Bits{}, Bits{}, nil},
|
||||
{Bits{0}, Bits{0}, Bits{0}},
|
||||
{Bits{0}, Bits{1}, Bits{1}},
|
||||
{Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
|
||||
{Bits{-1}, Bits{1}, Bits{0}},
|
||||
{Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}},
|
||||
} {
|
||||
got := fmt.Sprintf("%v", test.x.mul(test.y))
|
||||
want := fmt.Sprintf("%v", test.want)
|
||||
if got != want {
|
||||
t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// norm returns the normalized bits for x: It removes multiple equal entries
|
||||
// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
|
||||
// the result list for reproducible results.
|
||||
func (x Bits) norm() Bits {
|
||||
m := make(map[int]bool)
|
||||
for _, b := range x {
|
||||
for m[b] {
|
||||
m[b] = false
|
||||
b++
|
||||
}
|
||||
m[b] = true
|
||||
}
|
||||
var z Bits
|
||||
for b, set := range m {
|
||||
if set {
|
||||
z = append(z, b)
|
||||
}
|
||||
}
|
||||
sort.Ints([]int(z))
|
||||
return z
|
||||
}
|
||||
|
||||
func TestNormBits(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x, want Bits
|
||||
}{
|
||||
{nil, nil},
|
||||
{Bits{}, Bits{}},
|
||||
{Bits{0}, Bits{0}},
|
||||
{Bits{0, 0}, Bits{1}},
|
||||
{Bits{3, 1, 1}, Bits{2, 3}},
|
||||
{Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
|
||||
} {
|
||||
got := fmt.Sprintf("%v", test.x.norm())
|
||||
want := fmt.Sprintf("%v", test.want)
|
||||
if got != want {
|
||||
t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// round returns the Float value corresponding to x after rounding x
|
||||
// to prec bits according to mode.
|
||||
func (x Bits) round(prec uint, mode RoundingMode) *Float {
|
||||
x = x.norm()
|
||||
|
||||
// determine range
|
||||
var min, max int
|
||||
for i, b := range x {
|
||||
if i == 0 || b < min {
|
||||
min = b
|
||||
}
|
||||
if i == 0 || b > max {
|
||||
max = b
|
||||
}
|
||||
}
|
||||
prec0 := uint(max + 1 - min)
|
||||
if prec >= prec0 {
|
||||
return x.Float()
|
||||
}
|
||||
// prec < prec0
|
||||
|
||||
// determine bit 0, rounding, and sticky bit, and result bits z
|
||||
var bit0, rbit, sbit uint
|
||||
var z Bits
|
||||
r := max - int(prec)
|
||||
for _, b := range x {
|
||||
switch {
|
||||
case b == r:
|
||||
rbit = 1
|
||||
case b < r:
|
||||
sbit = 1
|
||||
default:
|
||||
// b > r
|
||||
if b == r+1 {
|
||||
bit0 = 1
|
||||
}
|
||||
z = append(z, b)
|
||||
}
|
||||
}
|
||||
|
||||
// round
|
||||
f := z.Float() // rounded to zero
|
||||
if mode == ToNearestAway {
|
||||
panic("not yet implemented")
|
||||
}
|
||||
if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
|
||||
// round away from zero
|
||||
f.SetMode(ToZero).SetPrec(prec)
|
||||
f.Add(f, Bits{int(r) + 1}.Float())
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Float returns the *Float z of the smallest possible precision such that
|
||||
// z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal,
|
||||
// they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
|
||||
func (bits Bits) Float() *Float {
|
||||
// handle 0
|
||||
if len(bits) == 0 {
|
||||
return new(Float)
|
||||
}
|
||||
// len(bits) > 0
|
||||
|
||||
// determine lsb exponent
|
||||
var min int
|
||||
for i, b := range bits {
|
||||
if i == 0 || b < min {
|
||||
min = b
|
||||
}
|
||||
}
|
||||
|
||||
// create bit pattern
|
||||
x := NewInt(0)
|
||||
for _, b := range bits {
|
||||
badj := b - min
|
||||
// propagate carry if necessary
|
||||
for x.Bit(badj) != 0 {
|
||||
x.SetBit(x, badj, 0)
|
||||
badj++
|
||||
}
|
||||
x.SetBit(x, badj, 1)
|
||||
}
|
||||
|
||||
// create corresponding float
|
||||
z := new(Float).SetInt(x) // normalized
|
||||
if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
|
||||
z.exp = int32(e)
|
||||
} else {
|
||||
// this should never happen for our test cases
|
||||
panic("exponent out of range")
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func TestFromBits(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
bits Bits
|
||||
want string
|
||||
}{
|
||||
// all different bit numbers
|
||||
{nil, "0"},
|
||||
{Bits{0}, "0x.8p1"},
|
||||
{Bits{1}, "0x.8p2"},
|
||||
{Bits{-1}, "0x.8p0"},
|
||||
{Bits{63}, "0x.8p64"},
|
||||
{Bits{33, -30}, "0x.8000000000000001p34"},
|
||||
{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"},
|
||||
|
||||
// multiple equal bit numbers
|
||||
{Bits{0, 0}, "0x.8p2"},
|
||||
{Bits{0, 0, 0, 0}, "0x.8p3"},
|
||||
{Bits{0, 1, 0}, "0x.8p3"},
|
||||
{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
|
||||
} {
|
||||
f := test.bits.Float()
|
||||
if got := f.Format('p', 0); got != test.want {
|
||||
t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// 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 prints execution times for the Mul benchmark
|
||||
// given different Karatsuba thresholds. The result may be
|
||||
// used to manually fine-tune the threshold constant. The
|
||||
// results are somewhat fragile; use repeated runs to get
|
||||
// a clear picture.
|
||||
|
||||
// Usage: go test -run=TestCalibrate -calibrate
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var calibrate = flag.Bool("calibrate", false, "run calibration test")
|
||||
|
||||
func karatsubaLoad(b *testing.B) {
|
||||
BenchmarkMul(b)
|
||||
}
|
||||
|
||||
// measureKaratsuba returns the time to run a Karatsuba-relevant benchmark
|
||||
// given Karatsuba threshold th.
|
||||
func measureKaratsuba(th int) time.Duration {
|
||||
th, karatsubaThreshold = karatsubaThreshold, th
|
||||
res := testing.Benchmark(karatsubaLoad)
|
||||
karatsubaThreshold = th
|
||||
return time.Duration(res.NsPerOp())
|
||||
}
|
||||
|
||||
func computeThresholds() {
|
||||
fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
|
||||
fmt.Printf("(run repeatedly for good results)\n")
|
||||
|
||||
// determine Tk, the work load execution time using basic multiplication
|
||||
Tb := measureKaratsuba(1e9) // th == 1e9 => Karatsuba multiplication disabled
|
||||
fmt.Printf("Tb = %10s\n", Tb)
|
||||
|
||||
// thresholds
|
||||
th := 4
|
||||
th1 := -1
|
||||
th2 := -1
|
||||
|
||||
var deltaOld time.Duration
|
||||
for count := -1; count != 0 && th < 128; count-- {
|
||||
// determine Tk, the work load execution time using Karatsuba multiplication
|
||||
Tk := measureKaratsuba(th)
|
||||
|
||||
// improvement over Tb
|
||||
delta := (Tb - Tk) * 100 / Tb
|
||||
|
||||
fmt.Printf("th = %3d Tk = %10s %4d%%", th, Tk, delta)
|
||||
|
||||
// determine break-even point
|
||||
if Tk < Tb && th1 < 0 {
|
||||
th1 = th
|
||||
fmt.Print(" break-even point")
|
||||
}
|
||||
|
||||
// determine diminishing return
|
||||
if 0 < delta && delta < deltaOld && th2 < 0 {
|
||||
th2 = th
|
||||
fmt.Print(" diminishing return")
|
||||
}
|
||||
deltaOld = delta
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// trigger counter
|
||||
if th1 >= 0 && th2 >= 0 && count < 0 {
|
||||
count = 10 // this many extra measurements after we got both thresholds
|
||||
}
|
||||
|
||||
th++
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalibrate(t *testing.T) {
|
||||
if *calibrate {
|
||||
computeThresholds()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
// Copyright 2015 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 decimal numbers.
|
||||
// The implementation is for float to decimal conversion only;
|
||||
// not general purpose use.
|
||||
// The only operations are precise conversion from binary to
|
||||
// decimal and rounding.
|
||||
//
|
||||
// The key observation and some code (shr) is borrowed from
|
||||
// strconv/decimal.go: conversion of binary fractional values can be done
|
||||
// precisely in multi-precision decimal because 2 divides 10 (required for
|
||||
// >> of mantissa); but conversion of decimal floating-point values cannot
|
||||
// be done precisely in binary representation.
|
||||
//
|
||||
// In contrast to strconv/decimal.go, only right shift is implemented in
|
||||
// decimal format - left shift can be done precisely in binary format.
|
||||
|
||||
package big
|
||||
|
||||
// A decimal represents a floating-point number in decimal representation.
|
||||
// The value of a decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
|
||||
// with the most-significant mantissa digit at index 0.
|
||||
type decimal struct {
|
||||
mant []byte // mantissa ASCII digits, big-endian
|
||||
exp int // exponent, valid if len(mant) > 0
|
||||
}
|
||||
|
||||
// Maximum shift amount that can be done in one pass without overflow.
|
||||
// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
|
||||
const maxShift = _W - 4
|
||||
|
||||
// TODO(gri) Since we know the desired decimal precision when converting
|
||||
// a floating-point number, we may be able to limit the number of decimal
|
||||
// digits that need to be computed by init by providing an additional
|
||||
// precision argument and keeping track of when a number was truncated early
|
||||
// (equivalent of "sticky bit" in binary rounding).
|
||||
|
||||
// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
|
||||
// to avoid "infinitely" long running conversions (until we run out of space).
|
||||
|
||||
// Init initializes x to the decimal representation of m << shift (for
|
||||
// shift >= 0), or m >> -shift (for shift < 0).
|
||||
func (x *decimal) init(m nat, shift int) {
|
||||
// special case 0
|
||||
if len(m) == 0 {
|
||||
x.mant = x.mant[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// Optimization: If we need to shift right, first remove any trailing
|
||||
// zero bits from m to reduce shift amount that needs to be done in
|
||||
// decimal format (since that is likely slower).
|
||||
if shift < 0 {
|
||||
ntz := m.trailingZeroBits()
|
||||
s := uint(-shift)
|
||||
if s >= ntz {
|
||||
s = ntz // shift at most ntz bits
|
||||
}
|
||||
m = nat(nil).shr(m, s)
|
||||
shift += int(s)
|
||||
}
|
||||
|
||||
// Do any shift left in binary representation.
|
||||
if shift > 0 {
|
||||
m = nat(nil).shl(m, uint(shift))
|
||||
shift = 0
|
||||
}
|
||||
|
||||
// Convert mantissa into decimal representation.
|
||||
s := m.decimalString() // TODO(gri) avoid string conversion here
|
||||
n := len(s)
|
||||
x.exp = n
|
||||
// Trim trailing zeros; instead the exponent is tracking
|
||||
// the decimal point independent of the number of digits.
|
||||
for n > 0 && s[n-1] == '0' {
|
||||
n--
|
||||
}
|
||||
x.mant = append(x.mant[:0], s[:n]...)
|
||||
|
||||
// Do any (remaining) shift right in decimal representation.
|
||||
if shift < 0 {
|
||||
for shift < -maxShift {
|
||||
shr(x, maxShift)
|
||||
shift += maxShift
|
||||
}
|
||||
shr(x, uint(-shift))
|
||||
}
|
||||
}
|
||||
|
||||
// Possibly optimization: The current implementation of nat.string takes
|
||||
// a charset argument. When a right shift is needed, we could provide
|
||||
// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
|
||||
// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
|
||||
// single +'0' pass at the end).
|
||||
|
||||
// shr implements x >> s, for s <= maxShift.
|
||||
func shr(x *decimal, s uint) {
|
||||
// Division by 1<<s using shift-and-subtract algorithm.
|
||||
|
||||
// pick up enough leading digits to cover first shift
|
||||
r := 0 // read index
|
||||
var n Word
|
||||
for n>>s == 0 && r < len(x.mant) {
|
||||
ch := Word(x.mant[r])
|
||||
r++
|
||||
n = n*10 + ch - '0'
|
||||
}
|
||||
if n == 0 {
|
||||
// x == 0; shouldn't get here, but handle anyway
|
||||
x.mant = x.mant[:0]
|
||||
return
|
||||
}
|
||||
for n>>s == 0 {
|
||||
r++
|
||||
n *= 10
|
||||
}
|
||||
x.exp += 1 - r
|
||||
|
||||
// read a digit, write a digit
|
||||
w := 0 // write index
|
||||
for r < len(x.mant) {
|
||||
ch := Word(x.mant[r])
|
||||
r++
|
||||
d := n >> s
|
||||
n -= d << s
|
||||
x.mant[w] = byte(d + '0')
|
||||
w++
|
||||
n = n*10 + ch - '0'
|
||||
}
|
||||
|
||||
// write extra digits that still fit
|
||||
for n > 0 && w < len(x.mant) {
|
||||
d := n >> s
|
||||
n -= d << s
|
||||
x.mant[w] = byte(d + '0')
|
||||
w++
|
||||
n = n * 10
|
||||
}
|
||||
x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
|
||||
|
||||
// append additional digits that didn't fit
|
||||
for n > 0 {
|
||||
d := n >> s
|
||||
n -= d << s
|
||||
x.mant = append(x.mant, byte(d+'0'))
|
||||
n = n * 10
|
||||
}
|
||||
|
||||
trim(x)
|
||||
}
|
||||
|
||||
func (x *decimal) String() string {
|
||||
if len(x.mant) == 0 {
|
||||
return "0"
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
switch {
|
||||
case x.exp <= 0:
|
||||
// 0.00ddd
|
||||
buf = append(buf, "0."...)
|
||||
buf = appendZeros(buf, -x.exp)
|
||||
buf = append(buf, x.mant...)
|
||||
|
||||
case /* 0 < */ x.exp < len(x.mant):
|
||||
// dd.ddd
|
||||
buf = append(buf, x.mant[:x.exp]...)
|
||||
buf = append(buf, '.')
|
||||
buf = append(buf, x.mant[x.exp:]...)
|
||||
|
||||
default: // len(x.mant) <= x.exp
|
||||
// ddd00
|
||||
buf = append(buf, x.mant...)
|
||||
buf = appendZeros(buf, x.exp-len(x.mant))
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// appendZeros appends n 0 digits to buf and returns buf.
|
||||
func appendZeros(buf []byte, n int) []byte {
|
||||
for ; n > 0; n-- {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// shouldRoundUp reports if x should be rounded up
|
||||
// if shortened to n digits. n must be a valid index
|
||||
// for x.mant.
|
||||
func shouldRoundUp(x *decimal, n int) bool {
|
||||
if x.mant[n] == '5' && n+1 == len(x.mant) {
|
||||
// exactly halfway - round to even
|
||||
return n > 0 && (x.mant[n-1]-'0')&1 != 0
|
||||
}
|
||||
// not halfway - digit tells all (x.mant has no trailing zeros)
|
||||
return x.mant[n] >= '5'
|
||||
}
|
||||
|
||||
// round sets x to (at most) n mantissa digits by rounding it
|
||||
// to the nearest even value with n (or fever) mantissa digits.
|
||||
// If n < 0, x remains unchanged.
|
||||
func (x *decimal) round(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
|
||||
if shouldRoundUp(x, n) {
|
||||
x.roundUp(n)
|
||||
} else {
|
||||
x.roundDown(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *decimal) roundUp(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
// 0 <= n < len(x.mant)
|
||||
|
||||
// find first digit < '9'
|
||||
for n > 0 && x.mant[n-1] >= '9' {
|
||||
n--
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
// all digits are '9's => round up to '1' and update exponent
|
||||
x.mant[0] = '1' // ok since len(x.mant) > n
|
||||
x.mant = x.mant[:1]
|
||||
x.exp++
|
||||
return
|
||||
}
|
||||
|
||||
// n > 0 && x.mant[n-1] < '9'
|
||||
x.mant[n-1]++
|
||||
x.mant = x.mant[:n]
|
||||
// x already trimmed
|
||||
}
|
||||
|
||||
func (x *decimal) roundDown(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
x.mant = x.mant[:n]
|
||||
trim(x)
|
||||
}
|
||||
|
||||
// trim cuts off any trailing zeros from x's mantissa;
|
||||
// they are meaningless for the value of x.
|
||||
func trim(x *decimal) {
|
||||
i := len(x.mant)
|
||||
for i > 0 && x.mant[i-1] == '0' {
|
||||
i--
|
||||
}
|
||||
x.mant = x.mant[:i]
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDecimalString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x decimal
|
||||
want string
|
||||
}{
|
||||
{want: "0"},
|
||||
{decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
|
||||
{decimal{[]byte("12345"), 0}, "0.12345"},
|
||||
{decimal{[]byte("12345"), -3}, "0.00012345"},
|
||||
{decimal{[]byte("12345"), +3}, "123.45"},
|
||||
{decimal{[]byte("12345"), +10}, "1234500000"},
|
||||
} {
|
||||
if got := test.x.String(); got != test.want {
|
||||
t.Errorf("%v == %s; want %s", test.x, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecimalInit(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x Word
|
||||
shift int
|
||||
want string
|
||||
}{
|
||||
{0, 0, "0"},
|
||||
{0, -100, "0"},
|
||||
{0, 100, "0"},
|
||||
{1, 0, "1"},
|
||||
{1, 10, "1024"},
|
||||
{1, 100, "1267650600228229401496703205376"},
|
||||
{1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
|
||||
{12345678, 8, "3160493568"},
|
||||
{12345678, -8, "48225.3046875"},
|
||||
{195312, 9, "99999744"},
|
||||
{1953125, 9, "1000000000"},
|
||||
} {
|
||||
var d decimal
|
||||
d.init(nat{test.x}.norm(), test.shift)
|
||||
if got := d.String(); got != test.want {
|
||||
t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecimalRounding(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x uint64
|
||||
n int
|
||||
down, even, up string
|
||||
}{
|
||||
{0, 0, "0", "0", "0"},
|
||||
{0, 1, "0", "0", "0"},
|
||||
|
||||
{1, 0, "0", "0", "10"},
|
||||
{5, 0, "0", "0", "10"},
|
||||
{9, 0, "0", "10", "10"},
|
||||
|
||||
{15, 1, "10", "20", "20"},
|
||||
{45, 1, "40", "40", "50"},
|
||||
{95, 1, "90", "100", "100"},
|
||||
|
||||
{12344999, 4, "12340000", "12340000", "12350000"},
|
||||
{12345000, 4, "12340000", "12340000", "12350000"},
|
||||
{12345001, 4, "12340000", "12350000", "12350000"},
|
||||
{23454999, 4, "23450000", "23450000", "23460000"},
|
||||
{23455000, 4, "23450000", "23460000", "23460000"},
|
||||
{23455001, 4, "23450000", "23460000", "23460000"},
|
||||
|
||||
{99994999, 4, "99990000", "99990000", "100000000"},
|
||||
{99995000, 4, "99990000", "100000000", "100000000"},
|
||||
{99999999, 4, "99990000", "100000000", "100000000"},
|
||||
|
||||
{12994999, 4, "12990000", "12990000", "13000000"},
|
||||
{12995000, 4, "12990000", "13000000", "13000000"},
|
||||
{12999999, 4, "12990000", "13000000", "13000000"},
|
||||
} {
|
||||
x := nat(nil).setUint64(test.x)
|
||||
|
||||
var d decimal
|
||||
d.init(x, 0)
|
||||
d.roundDown(test.n)
|
||||
if got := d.String(); got != test.down {
|
||||
t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
|
||||
}
|
||||
|
||||
d.init(x, 0)
|
||||
d.round(test.n)
|
||||
if got := d.String(); got != test.even {
|
||||
t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
|
||||
}
|
||||
|
||||
d.init(x, 0)
|
||||
d.roundUp(test.n)
|
||||
if got := d.String(); got != test.up {
|
||||
t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
|
||||
package big_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func ExampleRat_SetString() {
|
||||
r := new(big.Rat)
|
||||
r.SetString("355/113")
|
||||
fmt.Println(r.FloatString(3))
|
||||
// Output: 3.142
|
||||
}
|
||||
|
||||
func ExampleInt_SetString() {
|
||||
i := new(big.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(big.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(big.Int)
|
||||
_, err := fmt.Sscan("18446744073709551617", i)
|
||||
if err != nil {
|
||||
log.Println("error scanning value:", err)
|
||||
} else {
|
||||
fmt.Println(i)
|
||||
}
|
||||
// Output: 18446744073709551617
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,350 @@
|
|||
// Copyright 2015 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 float-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetString sets z to the value of s and returns z and a boolean indicating
|
||||
// success. s must be a floating-point number of the same format as accepted
|
||||
// by Scan, with number prefixes permitted.
|
||||
func (z *Float) SetString(s string) (*Float, bool) {
|
||||
r := strings.NewReader(s)
|
||||
|
||||
f, _, err := z.Scan(r, 0)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// there should be no unread characters left
|
||||
if _, err = r.ReadByte(); err != io.EOF {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return f, true
|
||||
}
|
||||
|
||||
// Scan scans the number corresponding to the longest possible prefix
|
||||
// of r representing a floating-point number with a mantissa in the
|
||||
// given conversion base (the exponent is always a decimal number).
|
||||
// It sets z to the (possibly rounded) value of the corresponding
|
||||
// floating-point number, and returns z, the actual base b, and an
|
||||
// error err, if any. If z's precision is 0, it is changed to 64
|
||||
// before rounding takes effect. The number must be of the form:
|
||||
//
|
||||
// number = [ sign ] [ prefix ] mantissa [ exponent ] .
|
||||
// sign = "+" | "-" .
|
||||
// prefix = "0" ( "x" | "X" | "b" | "B" ) .
|
||||
// mantissa = digits | digits "." [ digits ] | "." digits .
|
||||
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
|
||||
//
|
||||
// The base argument must be 0, 2, 10, or 16. Providing an invalid base
|
||||
// argument will lead to a run-time panic.
|
||||
//
|
||||
// For base 0, the number prefix determines the actual base: A prefix of
|
||||
// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
|
||||
// base 2; otherwise, the actual base is 10 and no prefix is accepted.
|
||||
// The octal prefix "0" is not supported (a leading "0" is simply
|
||||
// considered a "0").
|
||||
//
|
||||
// A "p" exponent indicates a binary (rather then decimal) exponent;
|
||||
// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
|
||||
// maximum float64 value. For hexadecimal mantissae, the exponent must
|
||||
// be binary, if present (an "e" or "E" exponent indicator cannot be
|
||||
// distinguished from a mantissa digit).
|
||||
//
|
||||
// The returned *Float f is nil and the value of z is valid but not
|
||||
// defined if an error is reported.
|
||||
//
|
||||
// BUG(gri) The Float.Scan signature conflicts with Scan(s fmt.ScanState, ch rune) error.
|
||||
func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
|
||||
prec := z.prec
|
||||
if prec == 0 {
|
||||
prec = 64
|
||||
}
|
||||
|
||||
// NaNs ignore sign, mantissa, and exponent so we can set
|
||||
// them below while having a valid value for z in case of
|
||||
// errors.
|
||||
z.SetNaN()
|
||||
|
||||
// sign
|
||||
z.neg, err = scanSign(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// mantissa
|
||||
var fcount int // fractional digit count; valid if <= 0
|
||||
z.mant, b, fcount, err = z.mant.scan(r, base, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// exponent
|
||||
var exp int64
|
||||
var ebase int
|
||||
exp, ebase, err = scanExponent(r, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// special-case 0
|
||||
if len(z.mant) == 0 {
|
||||
z.prec = prec
|
||||
z.acc = Exact
|
||||
z.form = zero
|
||||
f = z
|
||||
return
|
||||
}
|
||||
// len(z.mant) > 0
|
||||
|
||||
// The mantissa may have a decimal point (fcount <= 0) and there
|
||||
// may be a nonzero exponent exp. The decimal point amounts to a
|
||||
// division by b**(-fcount). An exponent means multiplication by
|
||||
// ebase**exp. Finally, mantissa normalization (shift left) requires
|
||||
// a correcting multiplication by 2**(-shiftcount). Multiplications
|
||||
// are commutative, so we can apply them in any order as long as there
|
||||
// is no loss of precision. We only have powers of 2 and 10; keep
|
||||
// track via separate exponents exp2 and exp10.
|
||||
|
||||
// normalize mantissa and get initial binary exponent
|
||||
var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
|
||||
|
||||
// determine binary or decimal exponent contribution of decimal point
|
||||
var exp10 int64
|
||||
if fcount < 0 {
|
||||
// The mantissa has a "decimal" point ddd.dddd; and
|
||||
// -fcount is the number of digits to the right of '.'.
|
||||
// Adjust relevant exponent accodingly.
|
||||
switch b {
|
||||
case 16:
|
||||
fcount *= 4 // hexadecimal digits are 4 bits each
|
||||
fallthrough
|
||||
case 2:
|
||||
exp2 += int64(fcount)
|
||||
default: // b == 10
|
||||
exp10 = int64(fcount)
|
||||
}
|
||||
// we don't need fcount anymore
|
||||
}
|
||||
|
||||
// take actual exponent into account
|
||||
if ebase == 2 {
|
||||
exp2 += exp
|
||||
} else { // ebase == 10
|
||||
exp10 += exp
|
||||
}
|
||||
// we don't need exp anymore
|
||||
|
||||
// apply 2**exp2
|
||||
if MinExp <= exp2 && exp2 <= MaxExp {
|
||||
z.prec = prec
|
||||
z.form = finite
|
||||
z.exp = int32(exp2)
|
||||
f = z
|
||||
} else {
|
||||
err = fmt.Errorf("exponent overflow")
|
||||
return
|
||||
}
|
||||
|
||||
if exp10 == 0 {
|
||||
// no decimal exponent to consider
|
||||
z.round(0)
|
||||
return
|
||||
}
|
||||
// exp10 != 0
|
||||
|
||||
// compute decimal exponent power
|
||||
expabs := exp10
|
||||
if expabs < 0 {
|
||||
expabs = -expabs
|
||||
}
|
||||
powTen := nat(nil).expNN(natTen, nat(nil).setUint64(uint64(expabs)), nil)
|
||||
fpowTen := new(Float).SetInt(new(Int).SetBits(powTen))
|
||||
|
||||
// apply 10**exp10
|
||||
if exp10 < 0 {
|
||||
z.uquo(z, fpowTen)
|
||||
} else {
|
||||
z.umul(z, fpowTen)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Parse is like z.Scan(r, base), but instead of reading from an
|
||||
// io.ByteScanner, it parses the string s. An error is also returned
|
||||
// if the string contains invalid or trailing bytes not belonging to
|
||||
// the number.
|
||||
func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
|
||||
r := strings.NewReader(s)
|
||||
|
||||
if f, b, err = z.Scan(r, base); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// entire string must have been consumed
|
||||
if ch, err2 := r.ReadByte(); err2 == nil {
|
||||
err = fmt.Errorf("expected end of string, found %q", ch)
|
||||
} else if err2 != io.EOF {
|
||||
err = err2
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ScanFloat is like f.Scan(r, base) with f set to the given precision
|
||||
// and rounding mode.
|
||||
func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
|
||||
return new(Float).SetPrec(prec).SetMode(mode).Scan(r, base)
|
||||
}
|
||||
|
||||
// ParseFloat is like f.Parse(s, base) with f set to the given precision
|
||||
// and rounding mode.
|
||||
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
|
||||
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
|
||||
}
|
||||
|
||||
// Format converts the floating-point number x to a string according
|
||||
// to the given format and precision prec. The format is one of:
|
||||
//
|
||||
// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
|
||||
// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
|
||||
// 'f' -ddddd.dddd, no exponent
|
||||
// 'g' like 'e' for large exponents, like 'f' otherwise
|
||||
// 'G' like 'E' for large exponents, like 'f' otherwise
|
||||
// 'b' -ddddddp±dd, binary exponent
|
||||
// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa
|
||||
//
|
||||
// For the binary exponent formats, the mantissa is printed in normalized form:
|
||||
//
|
||||
// 'b' decimal integer mantissa using x.Prec() bits, or -0
|
||||
// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
|
||||
//
|
||||
// The precision prec controls the number of digits (excluding the exponent)
|
||||
// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
|
||||
// it is the number of digits after the decimal point. For 'g' and 'G' it is
|
||||
// the total number of digits. A negative precision selects the smallest
|
||||
// number of digits necessary such that ParseFloat will return f exactly.
|
||||
// The prec value is ignored for the 'b' or 'p' format.
|
||||
//
|
||||
// BUG(gri) Float.Format does not accept negative precisions.
|
||||
func (x *Float) Format(format byte, prec int) string {
|
||||
const extra = 10 // TODO(gri) determine a good/better value here
|
||||
return string(x.Append(make([]byte, 0, prec+extra), format, prec))
|
||||
}
|
||||
|
||||
// Append appends the string form of the floating-point number x,
|
||||
// as generated by x.Format, to buf and returns the extended buffer.
|
||||
func (x *Float) Append(buf []byte, format byte, prec int) []byte {
|
||||
// TODO(gri) factor out handling of sign?
|
||||
|
||||
// Inf
|
||||
if x.IsInf() {
|
||||
var ch byte = '+'
|
||||
if x.neg {
|
||||
ch = '-'
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
return append(buf, "Inf"...)
|
||||
}
|
||||
|
||||
// NaN
|
||||
if x.IsNaN() {
|
||||
return append(buf, "NaN"...)
|
||||
}
|
||||
|
||||
// easy formats
|
||||
switch format {
|
||||
case 'b':
|
||||
return x.bstring(buf)
|
||||
case 'p':
|
||||
return x.pstring(buf)
|
||||
}
|
||||
|
||||
return x.bigFtoa(buf, format, prec)
|
||||
}
|
||||
|
||||
// BUG(gri): Float.String uses x.Format('g', 10) rather than x.Format('g', -1).
|
||||
func (x *Float) String() string {
|
||||
return x.Format('g', 10)
|
||||
}
|
||||
|
||||
// bstring appends the string of x in the format ["-"] mantissa "p" exponent
|
||||
// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
|
||||
// and returns the extended buffer.
|
||||
// The mantissa is normalized such that is uses x.Prec() bits in binary
|
||||
// representation.
|
||||
func (x *Float) bstring(buf []byte) []byte {
|
||||
if x.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// adjust mantissa to use exactly x.prec bits
|
||||
m := x.mant
|
||||
switch w := uint32(len(x.mant)) * _W; {
|
||||
case w < x.prec:
|
||||
m = nat(nil).shl(m, uint(x.prec-w))
|
||||
case w > x.prec:
|
||||
m = nat(nil).shr(m, uint(w-x.prec))
|
||||
}
|
||||
|
||||
buf = append(buf, m.decimalString()...)
|
||||
buf = append(buf, 'p')
|
||||
e := int64(x.exp) - int64(x.prec)
|
||||
if e >= 0 {
|
||||
buf = append(buf, '+')
|
||||
}
|
||||
return strconv.AppendInt(buf, e, 10)
|
||||
}
|
||||
|
||||
// pstring appends the string of x in the format ["-"] "0x." mantissa "p" exponent
|
||||
// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
|
||||
// ad returns the extended buffer.
|
||||
// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
|
||||
func (x *Float) pstring(buf []byte) []byte {
|
||||
if x.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// remove trailing 0 words early
|
||||
// (no need to convert to hex 0's and trim later)
|
||||
m := x.mant
|
||||
i := 0
|
||||
for i < len(m) && m[i] == 0 {
|
||||
i++
|
||||
}
|
||||
m = m[i:]
|
||||
|
||||
buf = append(buf, "0x."...)
|
||||
buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
|
||||
buf = append(buf, 'p')
|
||||
return strconv.AppendInt(buf, int64(x.exp), 10)
|
||||
}
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFloatSetFloat64String(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
s string
|
||||
x float64
|
||||
}{
|
||||
// basics
|
||||
{"0", 0},
|
||||
{"-0", -0},
|
||||
{"+0", 0},
|
||||
{"1", 1},
|
||||
{"-1", -1},
|
||||
{"+1", 1},
|
||||
{"1.234", 1.234},
|
||||
{"-1.234", -1.234},
|
||||
{"+1.234", 1.234},
|
||||
{".1", 0.1},
|
||||
{"1.", 1},
|
||||
{"+1.", 1},
|
||||
|
||||
// various zeros
|
||||
{"0e100", 0},
|
||||
{"-0e+100", 0},
|
||||
{"+0e-100", 0},
|
||||
{"0E100", 0},
|
||||
{"-0E+100", 0},
|
||||
{"+0E-100", 0},
|
||||
|
||||
// various decimal exponent formats
|
||||
{"1.e10", 1e10},
|
||||
{"1e+10", 1e10},
|
||||
{"+1e-10", 1e-10},
|
||||
{"1E10", 1e10},
|
||||
{"1.E+10", 1e10},
|
||||
{"+1E-10", 1e-10},
|
||||
|
||||
// misc decimal values
|
||||
{"3.14159265", 3.14159265},
|
||||
{"-687436.79457e-245", -687436.79457e-245},
|
||||
{"-687436.79457E245", -687436.79457e245},
|
||||
{".0000000000000000000000000000000000000001", 1e-40},
|
||||
{"+10000000000000000000000000000000000000000e-0", 1e40},
|
||||
|
||||
// decimal mantissa, binary exponent
|
||||
{"0p0", 0},
|
||||
{"-0p0", -0},
|
||||
{"1p10", 1 << 10},
|
||||
{"1p+10", 1 << 10},
|
||||
{"+1p-10", 1.0 / (1 << 10)},
|
||||
{"1024p-12", 0.25},
|
||||
{"-1p10", -1024},
|
||||
{"1.5p1", 3},
|
||||
|
||||
// binary mantissa, decimal exponent
|
||||
{"0b0", 0},
|
||||
{"-0b0", -0},
|
||||
{"0b0e+10", 0},
|
||||
{"-0b0e-10", -0},
|
||||
{"0b1010", 10},
|
||||
{"0B1010E2", 1000},
|
||||
{"0b.1", 0.5},
|
||||
{"0b.001", 0.125},
|
||||
{"0b.001e3", 125},
|
||||
|
||||
// binary mantissa, binary exponent
|
||||
{"0b0p+10", 0},
|
||||
{"-0b0p-10", -0},
|
||||
{"0b.1010p4", 10},
|
||||
{"0b1p-1", 0.5},
|
||||
{"0b001p-3", 0.125},
|
||||
{"0b.001p3", 1},
|
||||
{"0b0.01p2", 1},
|
||||
|
||||
// hexadecimal mantissa and exponent
|
||||
{"0x0", 0},
|
||||
{"-0x0", -0},
|
||||
{"0x0p+10", 0},
|
||||
{"-0x0p-10", -0},
|
||||
{"0xff", 255},
|
||||
{"0X.8p1", 1},
|
||||
{"-0X0.00008p16", -0.5},
|
||||
{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64},
|
||||
{"0x1.fffffffffffffp1023", math.MaxFloat64},
|
||||
} {
|
||||
var x Float
|
||||
x.SetPrec(53)
|
||||
_, ok := x.SetString(test.s)
|
||||
if !ok {
|
||||
t.Errorf("%s: parse error", test.s)
|
||||
continue
|
||||
}
|
||||
f, _ := x.Float64()
|
||||
want := new(Float).SetFloat64(test.x)
|
||||
if x.Cmp(want).Neq() {
|
||||
t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
below1e23 = 99999999999999974834176
|
||||
above1e23 = 100000000000000008388608
|
||||
)
|
||||
|
||||
func TestFloat64Format(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x float64
|
||||
format byte
|
||||
prec int
|
||||
want string
|
||||
}{
|
||||
{0, 'f', 0, "0"},
|
||||
{math.Copysign(0, -1), 'f', 0, "-0"},
|
||||
{1, 'f', 0, "1"},
|
||||
{-1, 'f', 0, "-1"},
|
||||
|
||||
{1.459, 'e', 0, "1e+00"},
|
||||
{2.459, 'e', 1, "2.5e+00"},
|
||||
{3.459, 'e', 2, "3.46e+00"},
|
||||
{4.459, 'e', 3, "4.459e+00"},
|
||||
{5.459, 'e', 4, "5.4590e+00"},
|
||||
|
||||
{1.459, 'f', 0, "1"},
|
||||
{2.459, 'f', 1, "2.5"},
|
||||
{3.459, 'f', 2, "3.46"},
|
||||
{4.459, 'f', 3, "4.459"},
|
||||
{5.459, 'f', 4, "5.4590"},
|
||||
|
||||
{0, 'b', 0, "0"},
|
||||
{math.Copysign(0, -1), 'b', 0, "-0"},
|
||||
{1.0, 'b', 0, "4503599627370496p-52"},
|
||||
{-1.0, 'b', 0, "-4503599627370496p-52"},
|
||||
{4503599627370496, 'b', 0, "4503599627370496p+0"},
|
||||
|
||||
{0, 'p', 0, "0"},
|
||||
{math.Copysign(0, -1), 'p', 0, "-0"},
|
||||
{1024.0, 'p', 0, "0x.8p11"},
|
||||
{-1024.0, 'p', 0, "-0x.8p11"},
|
||||
|
||||
// all test cases below from strconv/ftoa_test.go
|
||||
{1, 'e', 5, "1.00000e+00"},
|
||||
{1, 'f', 5, "1.00000"},
|
||||
{1, 'g', 5, "1"},
|
||||
// {1, 'g', -1, "1"},
|
||||
// {20, 'g', -1, "20"},
|
||||
// {1234567.8, 'g', -1, "1.2345678e+06"},
|
||||
// {200000, 'g', -1, "200000"},
|
||||
// {2000000, 'g', -1, "2e+06"},
|
||||
|
||||
// g conversion and zero suppression
|
||||
{400, 'g', 2, "4e+02"},
|
||||
{40, 'g', 2, "40"},
|
||||
{4, 'g', 2, "4"},
|
||||
{.4, 'g', 2, "0.4"},
|
||||
{.04, 'g', 2, "0.04"},
|
||||
{.004, 'g', 2, "0.004"},
|
||||
{.0004, 'g', 2, "0.0004"},
|
||||
{.00004, 'g', 2, "4e-05"},
|
||||
{.000004, 'g', 2, "4e-06"},
|
||||
|
||||
{0, 'e', 5, "0.00000e+00"},
|
||||
{0, 'f', 5, "0.00000"},
|
||||
{0, 'g', 5, "0"},
|
||||
// {0, 'g', -1, "0"},
|
||||
|
||||
{-1, 'e', 5, "-1.00000e+00"},
|
||||
{-1, 'f', 5, "-1.00000"},
|
||||
{-1, 'g', 5, "-1"},
|
||||
// {-1, 'g', -1, "-1"},
|
||||
|
||||
{12, 'e', 5, "1.20000e+01"},
|
||||
{12, 'f', 5, "12.00000"},
|
||||
{12, 'g', 5, "12"},
|
||||
// {12, 'g', -1, "12"},
|
||||
|
||||
{123456700, 'e', 5, "1.23457e+08"},
|
||||
{123456700, 'f', 5, "123456700.00000"},
|
||||
{123456700, 'g', 5, "1.2346e+08"},
|
||||
// {123456700, 'g', -1, "1.234567e+08"},
|
||||
|
||||
{1.2345e6, 'e', 5, "1.23450e+06"},
|
||||
{1.2345e6, 'f', 5, "1234500.00000"},
|
||||
{1.2345e6, 'g', 5, "1.2345e+06"},
|
||||
|
||||
{1e23, 'e', 17, "9.99999999999999916e+22"},
|
||||
{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
|
||||
{1e23, 'g', 17, "9.9999999999999992e+22"},
|
||||
|
||||
// {1e23, 'e', -1, "1e+23"},
|
||||
// {1e23, 'f', -1, "100000000000000000000000"},
|
||||
// {1e23, 'g', -1, "1e+23"},
|
||||
|
||||
{below1e23, 'e', 17, "9.99999999999999748e+22"},
|
||||
{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
|
||||
{below1e23, 'g', 17, "9.9999999999999975e+22"},
|
||||
|
||||
// {below1e23, 'e', -1, "9.999999999999997e+22"},
|
||||
// {below1e23, 'f', -1, "99999999999999970000000"},
|
||||
// {below1e23, 'g', -1, "9.999999999999997e+22"},
|
||||
|
||||
{above1e23, 'e', 17, "1.00000000000000008e+23"},
|
||||
{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
|
||||
// {above1e23, 'g', 17, "1.0000000000000001e+23"},
|
||||
|
||||
// {above1e23, 'e', -1, "1.0000000000000001e+23"},
|
||||
// {above1e23, 'f', -1, "100000000000000010000000"},
|
||||
// {above1e23, 'g', -1, "1.0000000000000001e+23"},
|
||||
|
||||
// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
|
||||
// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
|
||||
|
||||
// {32, 'g', -1, "32"},
|
||||
// {32, 'g', 0, "3e+01"},
|
||||
|
||||
// {100, 'x', -1, "%x"},
|
||||
|
||||
// {math.NaN(), 'g', -1, "NaN"},
|
||||
// {-math.NaN(), 'g', -1, "NaN"},
|
||||
{math.Inf(0), 'g', -1, "+Inf"},
|
||||
{math.Inf(-1), 'g', -1, "-Inf"},
|
||||
{-math.Inf(0), 'g', -1, "-Inf"},
|
||||
|
||||
{-1, 'b', -1, "-4503599627370496p-52"},
|
||||
|
||||
// fixed bugs
|
||||
{0.9, 'f', 1, "0.9"},
|
||||
{0.09, 'f', 1, "0.1"},
|
||||
{0.0999, 'f', 1, "0.1"},
|
||||
{0.05, 'f', 1, "0.1"},
|
||||
{0.05, 'f', 0, "0"},
|
||||
{0.5, 'f', 1, "0.5"},
|
||||
{0.5, 'f', 0, "0"},
|
||||
{1.5, 'f', 0, "2"},
|
||||
|
||||
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
|
||||
// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
|
||||
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
|
||||
// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
|
||||
|
||||
// Issue 2625.
|
||||
{383260575764816448, 'f', 0, "383260575764816448"},
|
||||
// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
|
||||
} {
|
||||
f := new(Float).SetFloat64(test.x)
|
||||
got := f.Format(test.format, test.prec)
|
||||
if got != test.want {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.want)
|
||||
}
|
||||
|
||||
if test.format == 'b' && test.x == 0 {
|
||||
continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
|
||||
}
|
||||
if test.format == 'p' {
|
||||
continue // 'p' format not supported in strconv.Format
|
||||
}
|
||||
|
||||
// verify that Float format matches strconv format
|
||||
want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
|
||||
if got != want {
|
||||
t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatFormat(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
prec uint
|
||||
format byte
|
||||
digits int
|
||||
want string
|
||||
}{
|
||||
{"0", 10, 'f', 0, "0"},
|
||||
{"-0", 10, 'f', 0, "-0"},
|
||||
{"1", 10, 'f', 0, "1"},
|
||||
{"-1", 10, 'f', 0, "-1"},
|
||||
|
||||
{"1.459", 100, 'e', 0, "1e+00"},
|
||||
{"2.459", 100, 'e', 1, "2.5e+00"},
|
||||
{"3.459", 100, 'e', 2, "3.46e+00"},
|
||||
{"4.459", 100, 'e', 3, "4.459e+00"},
|
||||
{"5.459", 100, 'e', 4, "5.4590e+00"},
|
||||
|
||||
{"1.459", 100, 'E', 0, "1E+00"},
|
||||
{"2.459", 100, 'E', 1, "2.5E+00"},
|
||||
{"3.459", 100, 'E', 2, "3.46E+00"},
|
||||
{"4.459", 100, 'E', 3, "4.459E+00"},
|
||||
{"5.459", 100, 'E', 4, "5.4590E+00"},
|
||||
|
||||
{"1.459", 100, 'f', 0, "1"},
|
||||
{"2.459", 100, 'f', 1, "2.5"},
|
||||
{"3.459", 100, 'f', 2, "3.46"},
|
||||
{"4.459", 100, 'f', 3, "4.459"},
|
||||
{"5.459", 100, 'f', 4, "5.4590"},
|
||||
|
||||
{"1.459", 100, 'g', 0, "1"},
|
||||
{"2.459", 100, 'g', 1, "2"},
|
||||
{"3.459", 100, 'g', 2, "3.5"},
|
||||
{"4.459", 100, 'g', 3, "4.46"},
|
||||
{"5.459", 100, 'g', 4, "5.459"},
|
||||
|
||||
{"1459", 53, 'g', 0, "1e+03"},
|
||||
{"2459", 53, 'g', 1, "2e+03"},
|
||||
{"3459", 53, 'g', 2, "3.5e+03"},
|
||||
{"4459", 53, 'g', 3, "4.46e+03"},
|
||||
{"5459", 53, 'g', 4, "5459"},
|
||||
|
||||
{"1459", 53, 'G', 0, "1E+03"},
|
||||
{"2459", 53, 'G', 1, "2E+03"},
|
||||
{"3459", 53, 'G', 2, "3.5E+03"},
|
||||
{"4459", 53, 'G', 3, "4.46E+03"},
|
||||
{"5459", 53, 'G', 4, "5459"},
|
||||
|
||||
{"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
|
||||
{"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
|
||||
{"3", 10, 'g', 40, "3"},
|
||||
|
||||
{"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
|
||||
{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
|
||||
{"3e40", 100, 'g', 40, "3e+40"},
|
||||
|
||||
// TODO(gri) need tests for actual large Floats
|
||||
|
||||
{"0", 53, 'b', 0, "0"},
|
||||
{"-0", 53, 'b', 0, "-0"},
|
||||
{"1.0", 53, 'b', 0, "4503599627370496p-52"},
|
||||
{"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
|
||||
{"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
|
||||
|
||||
// issue 9939
|
||||
{"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
{"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
{"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
{"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
{"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
{"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
|
||||
|
||||
{"3", 350, 'p', 0, "0x.cp2"},
|
||||
{"03", 350, 'p', 0, "0x.cp2"},
|
||||
{"3.", 350, 'p', 0, "0x.cp2"},
|
||||
{"3.0", 350, 'p', 0, "0x.cp2"},
|
||||
{"3.00", 350, 'p', 0, "0x.cp2"},
|
||||
{"3.000", 350, 'p', 0, "0x.cp2"},
|
||||
|
||||
{"0", 64, 'p', 0, "0"},
|
||||
{"-0", 64, 'p', 0, "-0"},
|
||||
{"1024.0", 64, 'p', 0, "0x.8p11"},
|
||||
{"-1024.0", 64, 'p', 0, "-0x.8p11"},
|
||||
|
||||
// unsupported format
|
||||
{"3.14", 64, 'x', 0, "%x"},
|
||||
} {
|
||||
f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %s", test, err)
|
||||
continue
|
||||
}
|
||||
|
||||
got := f.Format(test.format, test.digits)
|
||||
if got != test.want {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.want)
|
||||
}
|
||||
|
||||
// compare with strconv.FormatFloat output if possible
|
||||
// ('p' format is not supported by strconv.FormatFloat,
|
||||
// and its output for 0.0 prints a biased exponent value
|
||||
// as in 0p-1074 which makes no sense to emulate here)
|
||||
if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
|
||||
f64, acc := f.Float64()
|
||||
if acc != Exact {
|
||||
t.Errorf("%v: expected exact conversion to float64", test)
|
||||
continue
|
||||
}
|
||||
got := strconv.FormatFloat(f64, test.format, test.digits, 64)
|
||||
if got != test.want {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2015 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 big_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func ExampleFloat_Add() {
|
||||
// Operating on numbers of different precision.
|
||||
var x, y, z big.Float
|
||||
x.SetInt64(1000) // x is automatically set to 64bit precision
|
||||
y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
|
||||
z.SetPrec(32)
|
||||
z.Add(&x, &y)
|
||||
fmt.Printf("x = %s (%s, prec = %d, acc = %s)\n", &x, x.Format('p', 0), x.Prec(), x.Acc())
|
||||
fmt.Printf("y = %s (%s, prec = %d, acc = %s)\n", &y, y.Format('p', 0), y.Prec(), y.Acc())
|
||||
fmt.Printf("z = %s (%s, prec = %d, acc = %s)\n", &z, z.Format('p', 0), z.Prec(), z.Acc())
|
||||
// Output:
|
||||
// x = 1000 (0x.fap10, prec = 64, acc = Exact)
|
||||
// y = 2.718281828 (0x.adf85458248cd8p2, prec = 53, acc = Exact)
|
||||
// z = 1002.718282 (0x.faadf854p10, prec = 32, acc = Below)
|
||||
}
|
||||
|
||||
func Example_Shift() {
|
||||
// Implementing Float "shift" by modifying the (binary) exponents directly.
|
||||
for s := -5; s <= 5; s++ {
|
||||
x := big.NewFloat(0.5)
|
||||
x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
|
||||
fmt.Println(x)
|
||||
}
|
||||
// Output:
|
||||
// 0.015625
|
||||
// 0.03125
|
||||
// 0.0625
|
||||
// 0.125
|
||||
// 0.25
|
||||
// 0.5
|
||||
// 1
|
||||
// 2
|
||||
// 4
|
||||
// 8
|
||||
// 16
|
||||
}
|
||||
|
||||
func ExampleFloat_Cmp() {
|
||||
inf := math.Inf(1)
|
||||
zero := 0.0
|
||||
nan := math.NaN()
|
||||
|
||||
operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf, nan}
|
||||
|
||||
fmt.Println(" x y cmp eql neq lss leq gtr geq")
|
||||
fmt.Println("-----------------------------------------------")
|
||||
for _, x64 := range operands {
|
||||
x := big.NewFloat(x64)
|
||||
for _, y64 := range operands {
|
||||
y := big.NewFloat(y64)
|
||||
t := x.Cmp(y)
|
||||
fmt.Printf(
|
||||
"%4s %4s %5s %c %c %c %c %c %c\n",
|
||||
x, y, t.Acc(),
|
||||
mark(t.Eql()), mark(t.Neq()), mark(t.Lss()), mark(t.Leq()), mark(t.Gtr()), mark(t.Geq()))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// x y cmp eql neq lss leq gtr geq
|
||||
// -----------------------------------------------
|
||||
// -Inf -Inf Exact ● ○ ○ ● ○ ●
|
||||
// -Inf -1.2 Below ○ ● ● ● ○ ○
|
||||
// -Inf -0 Below ○ ● ● ● ○ ○
|
||||
// -Inf 0 Below ○ ● ● ● ○ ○
|
||||
// -Inf 1.2 Below ○ ● ● ● ○ ○
|
||||
// -Inf +Inf Below ○ ● ● ● ○ ○
|
||||
// -Inf NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// -1.2 -Inf Above ○ ● ○ ○ ● ●
|
||||
// -1.2 -1.2 Exact ● ○ ○ ● ○ ●
|
||||
// -1.2 -0 Below ○ ● ● ● ○ ○
|
||||
// -1.2 0 Below ○ ● ● ● ○ ○
|
||||
// -1.2 1.2 Below ○ ● ● ● ○ ○
|
||||
// -1.2 +Inf Below ○ ● ● ● ○ ○
|
||||
// -1.2 NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// -0 -Inf Above ○ ● ○ ○ ● ●
|
||||
// -0 -1.2 Above ○ ● ○ ○ ● ●
|
||||
// -0 -0 Exact ● ○ ○ ● ○ ●
|
||||
// -0 0 Exact ● ○ ○ ● ○ ●
|
||||
// -0 1.2 Below ○ ● ● ● ○ ○
|
||||
// -0 +Inf Below ○ ● ● ● ○ ○
|
||||
// -0 NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// 0 -Inf Above ○ ● ○ ○ ● ●
|
||||
// 0 -1.2 Above ○ ● ○ ○ ● ●
|
||||
// 0 -0 Exact ● ○ ○ ● ○ ●
|
||||
// 0 0 Exact ● ○ ○ ● ○ ●
|
||||
// 0 1.2 Below ○ ● ● ● ○ ○
|
||||
// 0 +Inf Below ○ ● ● ● ○ ○
|
||||
// 0 NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// 1.2 -Inf Above ○ ● ○ ○ ● ●
|
||||
// 1.2 -1.2 Above ○ ● ○ ○ ● ●
|
||||
// 1.2 -0 Above ○ ● ○ ○ ● ●
|
||||
// 1.2 0 Above ○ ● ○ ○ ● ●
|
||||
// 1.2 1.2 Exact ● ○ ○ ● ○ ●
|
||||
// 1.2 +Inf Below ○ ● ● ● ○ ○
|
||||
// 1.2 NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// +Inf -Inf Above ○ ● ○ ○ ● ●
|
||||
// +Inf -1.2 Above ○ ● ○ ○ ● ●
|
||||
// +Inf -0 Above ○ ● ○ ○ ● ●
|
||||
// +Inf 0 Above ○ ● ○ ○ ● ●
|
||||
// +Inf 1.2 Above ○ ● ○ ○ ● ●
|
||||
// +Inf +Inf Exact ● ○ ○ ● ○ ●
|
||||
// +Inf NaN Undef ○ ● ○ ○ ○ ○
|
||||
//
|
||||
// NaN -Inf Undef ○ ● ○ ○ ○ ○
|
||||
// NaN -1.2 Undef ○ ● ○ ○ ○ ○
|
||||
// NaN -0 Undef ○ ● ○ ○ ○ ○
|
||||
// NaN 0 Undef ○ ● ○ ○ ○ ○
|
||||
// NaN 1.2 Undef ○ ● ○ ○ ○ ○
|
||||
// NaN +Inf Undef ○ ● ○ ○ ○ ○
|
||||
// NaN NaN Undef ○ ● ○ ○ ○ ○
|
||||
}
|
||||
|
||||
func mark(p bool) rune {
|
||||
if p {
|
||||
return '●'
|
||||
}
|
||||
return '○'
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2015 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 the 'e', 'f', 'g' floating-point formats.
|
||||
// It is closely following the corresponding implementation in
|
||||
// strconv/ftoa.go, but modified and simplified for big.Float.
|
||||
|
||||
// Algorithm:
|
||||
// 1) convert Float to multiprecision decimal
|
||||
// 2) round to desired precision
|
||||
// 3) read digits out and format
|
||||
|
||||
package big
|
||||
|
||||
import "strconv"
|
||||
|
||||
// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
|
||||
|
||||
// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
|
||||
func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
|
||||
if debugFloat && !f.IsFinite() {
|
||||
panic("non-finite float")
|
||||
}
|
||||
|
||||
// 1) convert Float to multiprecision decimal
|
||||
var mant nat
|
||||
if f.form == finite {
|
||||
mant = f.mant
|
||||
}
|
||||
var d decimal
|
||||
d.init(mant, int(f.exp)-f.mant.bitLen())
|
||||
|
||||
// 2) round to desired precision
|
||||
shortest := false
|
||||
if prec < 0 {
|
||||
shortest = true
|
||||
panic("unimplemented")
|
||||
// TODO(gri) complete this
|
||||
// roundShortest(&d, f.mant, int(f.exp))
|
||||
// Precision for shortest representation mode.
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
prec = len(d.mant) - 1
|
||||
case 'f':
|
||||
prec = max(len(d.mant)-d.exp, 0)
|
||||
case 'g', 'G':
|
||||
prec = len(d.mant)
|
||||
}
|
||||
} else {
|
||||
// round appropriately
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
// one digit before and number of digits after decimal point
|
||||
d.round(1 + prec)
|
||||
case 'f':
|
||||
// number of digits before and after decimal point
|
||||
d.round(d.exp + prec)
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1
|
||||
}
|
||||
d.round(prec)
|
||||
}
|
||||
}
|
||||
|
||||
// 3) read digits out and format
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
return fmtE(buf, fmt, prec, f.neg, d)
|
||||
case 'f':
|
||||
return fmtF(buf, prec, f.neg, d)
|
||||
case 'g', 'G':
|
||||
// trim trailing fractional zeros in %e format
|
||||
eprec := prec
|
||||
if eprec > len(d.mant) && len(d.mant) >= d.exp {
|
||||
eprec = len(d.mant)
|
||||
}
|
||||
// %e is used if the exponent from the conversion
|
||||
// is less than -4 or greater than or equal to the precision.
|
||||
// If precision was the shortest possible, use eprec = 6 for
|
||||
// this decision.
|
||||
if shortest {
|
||||
eprec = 6
|
||||
}
|
||||
exp := d.exp - 1
|
||||
if exp < -4 || exp >= eprec {
|
||||
if prec > len(d.mant) {
|
||||
prec = len(d.mant)
|
||||
}
|
||||
return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
|
||||
}
|
||||
if prec > d.exp {
|
||||
prec = len(d.mant)
|
||||
}
|
||||
return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
|
||||
}
|
||||
|
||||
// unknown format
|
||||
return append(buf, '%', fmt)
|
||||
}
|
||||
|
||||
// %e: -d.ddddde±dd
|
||||
func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
|
||||
// sign
|
||||
if neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
|
||||
// first digit
|
||||
ch := byte('0')
|
||||
if len(d.mant) > 0 {
|
||||
ch = d.mant[0]
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
|
||||
// .moredigits
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
i := 1
|
||||
m := min(len(d.mant), prec+1)
|
||||
if i < m {
|
||||
buf = append(buf, d.mant[i:m]...)
|
||||
i = m
|
||||
}
|
||||
for ; i <= prec; i++ {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
}
|
||||
|
||||
// e±
|
||||
buf = append(buf, fmt)
|
||||
var exp int64
|
||||
if len(d.mant) > 0 {
|
||||
exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
|
||||
}
|
||||
if exp < 0 {
|
||||
ch = '-'
|
||||
exp = -exp
|
||||
} else {
|
||||
ch = '+'
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
|
||||
// dd...d
|
||||
if exp < 10 {
|
||||
buf = append(buf, '0') // at least 2 exponent digits
|
||||
}
|
||||
return strconv.AppendInt(buf, exp, 10)
|
||||
}
|
||||
|
||||
// %f: -ddddddd.ddddd
|
||||
func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
|
||||
// sign
|
||||
if neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
|
||||
// integer, padded with zeros as needed
|
||||
if d.exp > 0 {
|
||||
m := min(len(d.mant), d.exp)
|
||||
buf = append(buf, d.mant[:m]...)
|
||||
for ; m < d.exp; m++ {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
} else {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
|
||||
// fraction
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
for i := 0; i < prec; i++ {
|
||||
ch := byte('0')
|
||||
if j := d.exp + i; 0 <= j && j < len(d.mant) {
|
||||
ch = d.mant[j]
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
}
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
// This file implements a GCD benchmark.
|
||||
// Usage: go test math/big -test.bench GCD
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// randInt returns a pseudo-random Int in the range [1<<(size-1), (1<<size) - 1]
|
||||
func randInt(r *rand.Rand, size uint) *Int {
|
||||
n := new(Int).Lsh(intOne, size-1)
|
||||
x := new(Int).Rand(r, n)
|
||||
return x.Add(x, n) // make sure result > 1<<(size-1)
|
||||
}
|
||||
|
||||
func runGCD(b *testing.B, aSize, bSize uint) {
|
||||
b.StopTimer()
|
||||
var r = rand.New(rand.NewSource(1234))
|
||||
aa := randInt(r, aSize)
|
||||
bb := randInt(r, bSize)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
new(Int).GCD(nil, nil, aa, bb)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGCD10x10(b *testing.B) { runGCD(b, 10, 10) }
|
||||
func BenchmarkGCD10x100(b *testing.B) { runGCD(b, 10, 100) }
|
||||
func BenchmarkGCD10x1000(b *testing.B) { runGCD(b, 10, 1000) }
|
||||
func BenchmarkGCD10x10000(b *testing.B) { runGCD(b, 10, 10000) }
|
||||
func BenchmarkGCD10x100000(b *testing.B) { runGCD(b, 10, 100000) }
|
||||
func BenchmarkGCD100x100(b *testing.B) { runGCD(b, 100, 100) }
|
||||
func BenchmarkGCD100x1000(b *testing.B) { runGCD(b, 100, 1000) }
|
||||
func BenchmarkGCD100x10000(b *testing.B) { runGCD(b, 100, 10000) }
|
||||
func BenchmarkGCD100x100000(b *testing.B) { runGCD(b, 100, 100000) }
|
||||
func BenchmarkGCD1000x1000(b *testing.B) { runGCD(b, 1000, 1000) }
|
||||
func BenchmarkGCD1000x10000(b *testing.B) { runGCD(b, 1000, 10000) }
|
||||
func BenchmarkGCD1000x100000(b *testing.B) { runGCD(b, 1000, 100000) }
|
||||
func BenchmarkGCD10000x10000(b *testing.B) { runGCD(b, 10000, 10000) }
|
||||
func BenchmarkGCD10000x100000(b *testing.B) { runGCD(b, 10000, 100000) }
|
||||
func BenchmarkGCD100000x100000(b *testing.B) { runGCD(b, 100000, 100000) }
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
// 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.
|
||||
|
||||
// A little test program and benchmark for rational arithmetics.
|
||||
// Computes a Hilbert matrix, its inverse, multiplies them
|
||||
// and verifies that the product is the identity matrix.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type matrix struct {
|
||||
n, m int
|
||||
a []*Rat
|
||||
}
|
||||
|
||||
func (a *matrix) at(i, j int) *Rat {
|
||||
if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
|
||||
panic("index out of range")
|
||||
}
|
||||
return a.a[i*a.m+j]
|
||||
}
|
||||
|
||||
func (a *matrix) set(i, j int, x *Rat) {
|
||||
if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
|
||||
panic("index out of range")
|
||||
}
|
||||
a.a[i*a.m+j] = x
|
||||
}
|
||||
|
||||
func newMatrix(n, m int) *matrix {
|
||||
if !(0 <= n && 0 <= m) {
|
||||
panic("illegal matrix")
|
||||
}
|
||||
a := new(matrix)
|
||||
a.n = n
|
||||
a.m = m
|
||||
a.a = make([]*Rat, n*m)
|
||||
return a
|
||||
}
|
||||
|
||||
func newUnit(n int) *matrix {
|
||||
a := newMatrix(n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
x := NewRat(0, 1)
|
||||
if i == j {
|
||||
x.SetInt64(1)
|
||||
}
|
||||
a.set(i, j, x)
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func newHilbert(n int) *matrix {
|
||||
a := newMatrix(n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
a.set(i, j, NewRat(1, int64(i+j+1)))
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func newInverseHilbert(n int) *matrix {
|
||||
a := newMatrix(n, n)
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
x1 := new(Rat).SetInt64(int64(i + j + 1))
|
||||
x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
|
||||
x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
|
||||
x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
|
||||
|
||||
x1.Mul(x1, x2)
|
||||
x1.Mul(x1, x3)
|
||||
x1.Mul(x1, x4)
|
||||
x1.Mul(x1, x4)
|
||||
|
||||
if (i+j)&1 != 0 {
|
||||
x1.Neg(x1)
|
||||
}
|
||||
|
||||
a.set(i, j, x1)
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *matrix) mul(b *matrix) *matrix {
|
||||
if a.m != b.n {
|
||||
panic("illegal matrix multiply")
|
||||
}
|
||||
c := newMatrix(a.n, b.m)
|
||||
for i := 0; i < c.n; i++ {
|
||||
for j := 0; j < c.m; j++ {
|
||||
x := NewRat(0, 1)
|
||||
for k := 0; k < a.m; k++ {
|
||||
x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
|
||||
}
|
||||
c.set(i, j, x)
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (a *matrix) eql(b *matrix) bool {
|
||||
if a.n != b.n || a.m != b.m {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < a.n; i++ {
|
||||
for j := 0; j < a.m; j++ {
|
||||
if a.at(i, j).Cmp(b.at(i, j)) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *matrix) String() string {
|
||||
s := ""
|
||||
for i := 0; i < a.n; i++ {
|
||||
for j := 0; j < a.m; j++ {
|
||||
s += fmt.Sprintf("\t%s", a.at(i, j))
|
||||
}
|
||||
s += "\n"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func doHilbert(t *testing.T, n int) {
|
||||
a := newHilbert(n)
|
||||
b := newInverseHilbert(n)
|
||||
I := newUnit(n)
|
||||
ab := a.mul(b)
|
||||
if !ab.eql(I) {
|
||||
if t == nil {
|
||||
panic("Hilbert failed")
|
||||
}
|
||||
t.Errorf("a = %s\n", a)
|
||||
t.Errorf("b = %s\n", b)
|
||||
t.Errorf("a*b = %s\n", ab)
|
||||
t.Errorf("I = %s\n", I)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHilbert(t *testing.T) {
|
||||
doHilbert(t, 10)
|
||||
}
|
||||
|
||||
func BenchmarkHilbert(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
doHilbert(nil, 10)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,845 @@
|
|||
// 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.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An Int represents a signed multi-precision integer.
|
||||
// The zero value for an Int represents the value 0.
|
||||
type Int struct {
|
||||
neg bool // sign
|
||||
abs nat // absolute value of the integer
|
||||
}
|
||||
|
||||
var intOne = &Int{false, natOne}
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if x < 0
|
||||
// 0 if x == 0
|
||||
// +1 if x > 0
|
||||
//
|
||||
func (x *Int) Sign() int {
|
||||
if len(x.abs) == 0 {
|
||||
return 0
|
||||
}
|
||||
if x.neg {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Int) SetInt64(x int64) *Int {
|
||||
neg := false
|
||||
if x < 0 {
|
||||
neg = true
|
||||
x = -x
|
||||
}
|
||||
z.abs = z.abs.setUint64(uint64(x))
|
||||
z.neg = neg
|
||||
return z
|
||||
}
|
||||
|
||||
// SetUint64 sets z to x and returns z.
|
||||
func (z *Int) SetUint64(x uint64) *Int {
|
||||
z.abs = z.abs.setUint64(x)
|
||||
z.neg = false
|
||||
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 {
|
||||
if z != x {
|
||||
z.abs = z.abs.set(x.abs)
|
||||
z.neg = x.neg
|
||||
}
|
||||
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 (x *Int) Bits() []Word {
|
||||
return x.abs
|
||||
}
|
||||
|
||||
// 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 {
|
||||
z.abs = nat(abs).norm()
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func (z *Int) Abs(x *Int) *Int {
|
||||
z.Set(x)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func (z *Int) Neg(x *Int) *Int {
|
||||
z.Set(x)
|
||||
z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
|
||||
return z
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func (z *Int) Add(x, y *Int) *Int {
|
||||
neg := x.neg
|
||||
if x.neg == y.neg {
|
||||
// x + y == x + y
|
||||
// (-x) + (-y) == -(x + y)
|
||||
z.abs = z.abs.add(x.abs, y.abs)
|
||||
} else {
|
||||
// x + (-y) == x - y == -(y - x)
|
||||
// (-x) + y == y - x == -(x - y)
|
||||
if x.abs.cmp(y.abs) >= 0 {
|
||||
z.abs = z.abs.sub(x.abs, y.abs)
|
||||
} else {
|
||||
neg = !neg
|
||||
z.abs = z.abs.sub(y.abs, x.abs)
|
||||
}
|
||||
}
|
||||
z.neg = len(z.abs) > 0 && neg // 0 has no sign
|
||||
return z
|
||||
}
|
||||
|
||||
// Sub sets z to the difference x-y and returns z.
|
||||
func (z *Int) Sub(x, y *Int) *Int {
|
||||
neg := x.neg
|
||||
if x.neg != y.neg {
|
||||
// x - (-y) == x + y
|
||||
// (-x) - y == -(x + y)
|
||||
z.abs = z.abs.add(x.abs, y.abs)
|
||||
} else {
|
||||
// x - y == x - y == -(y - x)
|
||||
// (-x) - (-y) == y - x == -(x - y)
|
||||
if x.abs.cmp(y.abs) >= 0 {
|
||||
z.abs = z.abs.sub(x.abs, y.abs)
|
||||
} else {
|
||||
neg = !neg
|
||||
z.abs = z.abs.sub(y.abs, x.abs)
|
||||
}
|
||||
}
|
||||
z.neg = len(z.abs) > 0 && neg // 0 has no sign
|
||||
return z
|
||||
}
|
||||
|
||||
// Mul sets z to the product x*y and returns z.
|
||||
func (z *Int) Mul(x, y *Int) *Int {
|
||||
// x * y == x * y
|
||||
// x * (-y) == -(x * y)
|
||||
// (-x) * y == -(x * y)
|
||||
// (-x) * (-y) == x * y
|
||||
z.abs = z.abs.mul(x.abs, y.abs)
|
||||
z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
|
||||
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)
|
||||
|
||||
neg := false
|
||||
if a < 0 {
|
||||
neg = (b-a)&1 == 0
|
||||
a, b = -b, -a
|
||||
}
|
||||
|
||||
z.abs = z.abs.mulRange(uint64(a), uint64(b))
|
||||
z.neg = neg
|
||||
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 {
|
||||
z.abs, _ = z.abs.div(nil, x.abs, y.abs)
|
||||
z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
|
||||
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 {
|
||||
_, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
|
||||
z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
|
||||
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) {
|
||||
z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
|
||||
z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
|
||||
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 {
|
||||
y_neg := y.neg // z may be an alias for y
|
||||
var r Int
|
||||
z.QuoRem(x, y, &r)
|
||||
if r.neg {
|
||||
if y_neg {
|
||||
z.Add(z, intOne)
|
||||
} else {
|
||||
z.Sub(z, intOne)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
y0 := y // save y
|
||||
if z == y || alias(z.abs, y.abs) {
|
||||
y0 = new(Int).Set(y)
|
||||
}
|
||||
var q Int
|
||||
q.QuoRem(x, y, z)
|
||||
if z.neg {
|
||||
if y0.neg {
|
||||
z.Sub(z, y0)
|
||||
} else {
|
||||
z.Add(z, y0)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
y0 := y // save y
|
||||
if z == y || alias(z.abs, y.abs) {
|
||||
y0 = new(Int).Set(y)
|
||||
}
|
||||
z.QuoRem(x, y, m)
|
||||
if m.neg {
|
||||
if y0.neg {
|
||||
z.Add(z, intOne)
|
||||
m.Sub(m, y0)
|
||||
} else {
|
||||
z.Sub(z, intOne)
|
||||
m.Add(m, y0)
|
||||
}
|
||||
}
|
||||
return z, m
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
//
|
||||
func (x *Int) Cmp(y *Int) (r int) {
|
||||
// x cmp y == x cmp y
|
||||
// x cmp (-y) == x
|
||||
// (-x) cmp y == y
|
||||
// (-x) cmp (-y) == -(x cmp y)
|
||||
switch {
|
||||
case x.neg == y.neg:
|
||||
r = x.abs.cmp(y.abs)
|
||||
if x.neg {
|
||||
r = -r
|
||||
}
|
||||
case x.neg:
|
||||
r = -1
|
||||
default:
|
||||
r = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// low32 returns the least significant 32 bits of z.
|
||||
func low32(z nat) uint32 {
|
||||
if len(z) == 0 {
|
||||
return 0
|
||||
}
|
||||
return uint32(z[0])
|
||||
}
|
||||
|
||||
// low64 returns the least significant 64 bits of z.
|
||||
func low64(z nat) uint64 {
|
||||
if len(z) == 0 {
|
||||
return 0
|
||||
}
|
||||
v := uint64(z[0])
|
||||
if _W == 32 && len(z) > 1 {
|
||||
v |= uint64(z[1]) << 32
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Int64 returns the int64 representation of x.
|
||||
// If x cannot be represented in an int64, the result is undefined.
|
||||
func (x *Int) Int64() int64 {
|
||||
v := int64(low64(x.abs))
|
||||
if x.neg {
|
||||
v = -v
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Uint64 returns the uint64 representation of x.
|
||||
// If x cannot be represented in a uint64, the result is undefined.
|
||||
func (x *Int) Uint64() uint64 {
|
||||
return low64(x.abs)
|
||||
}
|
||||
|
||||
// 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 between 2 and 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) {
|
||||
r := strings.NewReader(s)
|
||||
_, _, err := z.scan(r, base)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
_, err = r.ReadByte()
|
||||
if err != io.EOF {
|
||||
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.abs = z.abs.setBytes(buf)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Bytes returns the absolute value of x as a big-endian byte slice.
|
||||
func (x *Int) Bytes() []byte {
|
||||
buf := make([]byte, len(x.abs)*_S)
|
||||
return buf[x.abs.bytes(buf):]
|
||||
}
|
||||
|
||||
// BitLen returns the length of the absolute value of x in bits.
|
||||
// The bit length of 0 is 0.
|
||||
func (x *Int) BitLen() int {
|
||||
return x.abs.bitLen()
|
||||
}
|
||||
|
||||
// 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 mod |m|; 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 {
|
||||
var yWords nat
|
||||
if !y.neg {
|
||||
yWords = y.abs
|
||||
}
|
||||
// y >= 0
|
||||
|
||||
var mWords nat
|
||||
if m != nil {
|
||||
mWords = m.abs // m.abs may be nil for m == 0
|
||||
}
|
||||
|
||||
z.abs = z.abs.expNN(x.abs, yWords, mWords)
|
||||
z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
|
||||
if z.neg && len(mWords) > 0 {
|
||||
// make modulus result positive
|
||||
z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m|
|
||||
z.neg = false
|
||||
}
|
||||
|
||||
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 {
|
||||
if a.Sign() <= 0 || b.Sign() <= 0 {
|
||||
z.SetInt64(0)
|
||||
if x != nil {
|
||||
x.SetInt64(0)
|
||||
}
|
||||
if y != nil {
|
||||
y.SetInt64(0)
|
||||
}
|
||||
return z
|
||||
}
|
||||
if x == nil && y == nil {
|
||||
return z.binaryGCD(a, b)
|
||||
}
|
||||
|
||||
A := new(Int).Set(a)
|
||||
B := new(Int).Set(b)
|
||||
|
||||
X := new(Int)
|
||||
Y := new(Int).SetInt64(1)
|
||||
|
||||
lastX := new(Int).SetInt64(1)
|
||||
lastY := new(Int)
|
||||
|
||||
q := new(Int)
|
||||
temp := new(Int)
|
||||
|
||||
for len(B.abs) > 0 {
|
||||
r := new(Int)
|
||||
q, r = q.QuoRem(A, B, r)
|
||||
|
||||
A, B = B, r
|
||||
|
||||
temp.Set(X)
|
||||
X.Mul(X, q)
|
||||
X.neg = !X.neg
|
||||
X.Add(X, lastX)
|
||||
lastX.Set(temp)
|
||||
|
||||
temp.Set(Y)
|
||||
Y.Mul(Y, q)
|
||||
Y.neg = !Y.neg
|
||||
Y.Add(Y, lastY)
|
||||
lastY.Set(temp)
|
||||
}
|
||||
|
||||
if x != nil {
|
||||
*x = *lastX
|
||||
}
|
||||
|
||||
if y != nil {
|
||||
*y = *lastY
|
||||
}
|
||||
|
||||
*z = *A
|
||||
return z
|
||||
}
|
||||
|
||||
// binaryGCD sets z to the greatest common divisor of a and b, which both must
|
||||
// be > 0, and returns z.
|
||||
// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm B.
|
||||
func (z *Int) binaryGCD(a, b *Int) *Int {
|
||||
u := z
|
||||
v := new(Int)
|
||||
|
||||
// use one Euclidean iteration to ensure that u and v are approx. the same size
|
||||
switch {
|
||||
case len(a.abs) > len(b.abs):
|
||||
u.Set(b)
|
||||
v.Rem(a, b)
|
||||
case len(a.abs) < len(b.abs):
|
||||
u.Set(a)
|
||||
v.Rem(b, a)
|
||||
default:
|
||||
u.Set(a)
|
||||
v.Set(b)
|
||||
}
|
||||
|
||||
// v might be 0 now
|
||||
if len(v.abs) == 0 {
|
||||
return u
|
||||
}
|
||||
// u > 0 && v > 0
|
||||
|
||||
// determine largest k such that u = u' << k, v = v' << k
|
||||
k := u.abs.trailingZeroBits()
|
||||
if vk := v.abs.trailingZeroBits(); vk < k {
|
||||
k = vk
|
||||
}
|
||||
u.Rsh(u, k)
|
||||
v.Rsh(v, k)
|
||||
|
||||
// determine t (we know that u > 0)
|
||||
t := new(Int)
|
||||
if u.abs[0]&1 != 0 {
|
||||
// u is odd
|
||||
t.Neg(v)
|
||||
} else {
|
||||
t.Set(u)
|
||||
}
|
||||
|
||||
for len(t.abs) > 0 {
|
||||
// reduce t
|
||||
t.Rsh(t, t.abs.trailingZeroBits())
|
||||
if t.neg {
|
||||
v, t = t, v
|
||||
v.neg = len(v.abs) > 0 && !v.neg // 0 has no sign
|
||||
} else {
|
||||
u, t = t, u
|
||||
}
|
||||
t.Sub(u, v)
|
||||
}
|
||||
|
||||
return z.Lsh(u, k)
|
||||
}
|
||||
|
||||
// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
|
||||
// If it returns true, x is prime with probability 1 - 1/4^n.
|
||||
// If it returns false, x is not prime. n must be > 0.
|
||||
func (x *Int) ProbablyPrime(n int) bool {
|
||||
if n <= 0 {
|
||||
panic("non-positive n for ProbablyPrime")
|
||||
}
|
||||
return !x.neg && x.abs.probablyPrime(n)
|
||||
}
|
||||
|
||||
// Rand sets z to a pseudo-random number in [0, n) and returns z.
|
||||
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
|
||||
z.neg = false
|
||||
if n.neg == true || len(n.abs) == 0 {
|
||||
z.abs = nil
|
||||
return z
|
||||
}
|
||||
z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
|
||||
return z
|
||||
}
|
||||
|
||||
// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
|
||||
// and returns z. If g and n are not relatively prime, the result is undefined.
|
||||
func (z *Int) ModInverse(g, n *Int) *Int {
|
||||
var d Int
|
||||
d.GCD(z, nil, g, n)
|
||||
// x and y are such that g*x + n*y = d. Since g and n are
|
||||
// relatively prime, d = 1. Taking that modulo n results in
|
||||
// g*x = 1, therefore x is the inverse element.
|
||||
if z.neg {
|
||||
z.Add(z, n)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Lsh sets z = x << n and returns z.
|
||||
func (z *Int) Lsh(x *Int, n uint) *Int {
|
||||
z.abs = z.abs.shl(x.abs, n)
|
||||
z.neg = x.neg
|
||||
return z
|
||||
}
|
||||
|
||||
// Rsh sets z = x >> n and returns z.
|
||||
func (z *Int) Rsh(x *Int, n uint) *Int {
|
||||
if x.neg {
|
||||
// (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
|
||||
t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
|
||||
t = t.shr(t, n)
|
||||
z.abs = t.add(t, natOne)
|
||||
z.neg = true // z cannot be zero if x is negative
|
||||
return z
|
||||
}
|
||||
|
||||
z.abs = z.abs.shr(x.abs, n)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Bit returns the value of the i'th bit of x. That is, it
|
||||
// returns (x>>i)&1. The bit index i must be >= 0.
|
||||
func (x *Int) Bit(i int) uint {
|
||||
if i == 0 {
|
||||
// optimization for common case: odd/even test of x
|
||||
if len(x.abs) > 0 {
|
||||
return uint(x.abs[0] & 1) // bit 0 is same for -x
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if i < 0 {
|
||||
panic("negative bit index")
|
||||
}
|
||||
if x.neg {
|
||||
t := nat(nil).sub(x.abs, natOne)
|
||||
return t.bit(uint(i)) ^ 1
|
||||
}
|
||||
|
||||
return x.abs.bit(uint(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 i < 0 {
|
||||
panic("negative bit index")
|
||||
}
|
||||
if x.neg {
|
||||
t := z.abs.sub(x.abs, natOne)
|
||||
t = t.setBit(t, uint(i), b^1)
|
||||
z.abs = t.add(t, natOne)
|
||||
z.neg = len(z.abs) > 0
|
||||
return z
|
||||
}
|
||||
z.abs = z.abs.setBit(x.abs, uint(i), b)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// And sets z = x & y and returns z.
|
||||
func (z *Int) And(x, y *Int) *Int {
|
||||
if x.neg == y.neg {
|
||||
if x.neg {
|
||||
// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
|
||||
x1 := nat(nil).sub(x.abs, natOne)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
|
||||
z.neg = true // z cannot be zero if x and y are negative
|
||||
return z
|
||||
}
|
||||
|
||||
// x & y == x & y
|
||||
z.abs = z.abs.and(x.abs, y.abs)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// x.neg != y.neg
|
||||
if x.neg {
|
||||
x, y = y, x // & is symmetric
|
||||
}
|
||||
|
||||
// x & (-y) == x & ^(y-1) == x &^ (y-1)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.andNot(x.abs, y1)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// AndNot sets z = x &^ y and returns z.
|
||||
func (z *Int) AndNot(x, y *Int) *Int {
|
||||
if x.neg == y.neg {
|
||||
if x.neg {
|
||||
// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
|
||||
x1 := nat(nil).sub(x.abs, natOne)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.andNot(y1, x1)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// x &^ y == x &^ y
|
||||
z.abs = z.abs.andNot(x.abs, y.abs)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
if x.neg {
|
||||
// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
|
||||
x1 := nat(nil).sub(x.abs, natOne)
|
||||
z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
|
||||
z.neg = true // z cannot be zero if x is negative and y is positive
|
||||
return z
|
||||
}
|
||||
|
||||
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.and(x.abs, y1)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Or sets z = x | y and returns z.
|
||||
func (z *Int) Or(x, y *Int) *Int {
|
||||
if x.neg == y.neg {
|
||||
if x.neg {
|
||||
// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
|
||||
x1 := nat(nil).sub(x.abs, natOne)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
|
||||
z.neg = true // z cannot be zero if x and y are negative
|
||||
return z
|
||||
}
|
||||
|
||||
// x | y == x | y
|
||||
z.abs = z.abs.or(x.abs, y.abs)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// x.neg != y.neg
|
||||
if x.neg {
|
||||
x, y = y, x // | is symmetric
|
||||
}
|
||||
|
||||
// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
|
||||
z.neg = true // z cannot be zero if one of x or y is negative
|
||||
return z
|
||||
}
|
||||
|
||||
// Xor sets z = x ^ y and returns z.
|
||||
func (z *Int) Xor(x, y *Int) *Int {
|
||||
if x.neg == y.neg {
|
||||
if x.neg {
|
||||
// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
|
||||
x1 := nat(nil).sub(x.abs, natOne)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.xor(x1, y1)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// x ^ y == x ^ y
|
||||
z.abs = z.abs.xor(x.abs, y.abs)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// x.neg != y.neg
|
||||
if x.neg {
|
||||
x, y = y, x // ^ is symmetric
|
||||
}
|
||||
|
||||
// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||
y1 := nat(nil).sub(y.abs, natOne)
|
||||
z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
|
||||
z.neg = true // z cannot be zero if only one of x or y is negative
|
||||
return z
|
||||
}
|
||||
|
||||
// Not sets z = ^x and returns z.
|
||||
func (z *Int) Not(x *Int) *Int {
|
||||
if x.neg {
|
||||
// ^(-x) == ^(^(x-1)) == x-1
|
||||
z.abs = z.abs.sub(x.abs, natOne)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// ^x == -x-1 == -(x+1)
|
||||
z.abs = z.abs.add(x.abs, natOne)
|
||||
z.neg = true // z cannot be zero if x is positive
|
||||
return z
|
||||
}
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const intGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (x *Int) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
|
||||
i := x.abs.bytes(buf) - 1 // i >= 0
|
||||
b := intGobVersion << 1 // make space for sign bit
|
||||
if x.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[i] = b
|
||||
return buf[i:], nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Int) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Int{}
|
||||
return nil
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != intGobVersion {
|
||||
return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
|
||||
}
|
||||
z.neg = b&1 != 0
|
||||
z.abs = z.abs.setBytes(buf[1:])
|
||||
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(text []byte) error {
|
||||
// TODO(gri): get rid of the []byte/string conversions
|
||||
if _, ok := z.SetString(string(text), 0); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (z *Int) MarshalText() (text []byte, err error) {
|
||||
return []byte(z.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (z *Int) UnmarshalText(text []byte) error {
|
||||
if _, ok := z.SetString(string(text), 0); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright 2015 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 int-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func (x *Int) String() string {
|
||||
switch {
|
||||
case x == nil:
|
||||
return "<nil>"
|
||||
case x.neg:
|
||||
return "-" + x.abs.decimalString()
|
||||
}
|
||||
return x.abs.decimalString()
|
||||
}
|
||||
|
||||
func charset(ch rune) string {
|
||||
switch ch {
|
||||
case 'b':
|
||||
return lowercaseDigits[0:2]
|
||||
case 'o':
|
||||
return lowercaseDigits[0:8]
|
||||
case 'd', 's', 'v':
|
||||
return lowercaseDigits[0:10]
|
||||
case 'x':
|
||||
return lowercaseDigits[0:16]
|
||||
case 'X':
|
||||
return uppercaseDigits[0:16]
|
||||
}
|
||||
return "" // 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 (x *Int) Format(s fmt.State, ch rune) {
|
||||
cs := charset(ch)
|
||||
|
||||
// special cases
|
||||
switch {
|
||||
case cs == "":
|
||||
// unknown format
|
||||
fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
|
||||
return
|
||||
case x == nil:
|
||||
fmt.Fprint(s, "<nil>")
|
||||
return
|
||||
}
|
||||
|
||||
// determine sign character
|
||||
sign := ""
|
||||
switch {
|
||||
case x.neg:
|
||||
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 := x.abs.string(cs)
|
||||
|
||||
// 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 (x == 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 sets z to the integer value corresponding to the longest possible prefix
|
||||
// read from r representing a signed integer number in a given conversion base.
|
||||
// It returns z, the actual conversion base used, and an error, if any. In the
|
||||
// error case, the value of z is undefined but the returned value is nil. The
|
||||
// syntax follows the syntax of integer literals in Go.
|
||||
//
|
||||
// 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) scan(r io.ByteScanner, base int) (*Int, int, error) {
|
||||
// determine sign
|
||||
neg, err := scanSign(r)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// determine mantissa
|
||||
z.abs, base, _, err = z.abs.scan(r, base, false)
|
||||
if err != nil {
|
||||
return nil, base, err
|
||||
}
|
||||
z.neg = len(z.abs) > 0 && neg // 0 has no sign
|
||||
|
||||
return z, base, nil
|
||||
}
|
||||
|
||||
func scanSign(r io.ByteScanner) (neg bool, err error) {
|
||||
var ch byte
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch ch {
|
||||
case '-':
|
||||
neg = true
|
||||
case '+':
|
||||
// nothing to do
|
||||
default:
|
||||
r.UnreadByte()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// byteReader is a local wrapper around fmt.ScanState;
|
||||
// it implements the ByteReader interface.
|
||||
type byteReader struct {
|
||||
fmt.ScanState
|
||||
}
|
||||
|
||||
func (r byteReader) ReadByte() (byte, error) {
|
||||
ch, size, err := r.ReadRune()
|
||||
if size != 1 && err == nil {
|
||||
err = fmt.Errorf("invalid rune %#U", ch)
|
||||
}
|
||||
return byte(ch), err
|
||||
}
|
||||
|
||||
func (r byteReader) UnreadByte() error {
|
||||
return r.UnreadRune()
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
_, _, err := z.scan(byteReader{s}, base)
|
||||
return err
|
||||
}
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var stringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
base int
|
||||
val int64
|
||||
ok bool
|
||||
}{
|
||||
{in: "", ok: false},
|
||||
{in: "a", ok: false},
|
||||
{in: "z", ok: false},
|
||||
{in: "+", ok: false},
|
||||
{in: "-", ok: false},
|
||||
{in: "0b", ok: false},
|
||||
{in: "0x", ok: false},
|
||||
{in: "2", base: 2, ok: false},
|
||||
{in: "0b2", base: 0, ok: false},
|
||||
{in: "08", ok: false},
|
||||
{in: "8", base: 8, ok: false},
|
||||
{in: "0xg", base: 0, ok: false},
|
||||
{in: "g", base: 16, ok: false},
|
||||
{"0", "0", 0, 0, true},
|
||||
{"0", "0", 10, 0, true},
|
||||
{"0", "0", 16, 0, true},
|
||||
{"+0", "0", 0, 0, true},
|
||||
{"-0", "0", 0, 0, true},
|
||||
{"10", "10", 0, 10, true},
|
||||
{"10", "10", 10, 10, true},
|
||||
{"10", "10", 16, 16, true},
|
||||
{"-10", "-10", 16, -16, true},
|
||||
{"+10", "10", 16, 16, true},
|
||||
{"0x10", "16", 0, 16, true},
|
||||
{in: "0x10", base: 16, ok: false},
|
||||
{"-0x10", "-16", 0, -16, true},
|
||||
{"+0x10", "16", 0, 16, true},
|
||||
{"00", "0", 0, 0, true},
|
||||
{"0", "0", 8, 0, true},
|
||||
{"07", "7", 0, 7, true},
|
||||
{"7", "7", 8, 7, true},
|
||||
{"023", "19", 0, 19, true},
|
||||
{"23", "23", 8, 19, true},
|
||||
{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
|
||||
{"0b0", "0", 0, 0, true},
|
||||
{"-111", "-111", 2, -7, true},
|
||||
{"-0b111", "-7", 0, -7, true},
|
||||
{"0b1001010111", "599", 0, 0x257, true},
|
||||
{"1001010111", "1001010111", 2, 0x257, true},
|
||||
}
|
||||
|
||||
func format(base int) string {
|
||||
switch base {
|
||||
case 2:
|
||||
return "%b"
|
||||
case 8:
|
||||
return "%o"
|
||||
case 16:
|
||||
return "%x"
|
||||
}
|
||||
return "%d"
|
||||
}
|
||||
|
||||
func TestGetString(t *testing.T) {
|
||||
z := new(Int)
|
||||
for i, test := range stringTests {
|
||||
if !test.ok {
|
||||
continue
|
||||
}
|
||||
z.SetInt64(test.val)
|
||||
|
||||
if test.base == 10 {
|
||||
s := z.String()
|
||||
if s != test.out {
|
||||
t.Errorf("#%da got %s; want %s", i, s, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
s := fmt.Sprintf(format(test.base), z)
|
||||
if s != test.out {
|
||||
t.Errorf("#%db got %s; want %s", i, s, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetString(t *testing.T) {
|
||||
tmp := new(Int)
|
||||
for i, test := range stringTests {
|
||||
// initialize to a non-zero value so that issues with parsing
|
||||
// 0 are detected
|
||||
tmp.SetInt64(1234567890)
|
||||
n1, ok1 := new(Int).SetString(test.in, test.base)
|
||||
n2, ok2 := tmp.SetString(test.in, test.base)
|
||||
expected := NewInt(test.val)
|
||||
if ok1 != test.ok || ok2 != test.ok {
|
||||
t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
|
||||
continue
|
||||
}
|
||||
if !ok1 {
|
||||
if n1 != nil {
|
||||
t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !ok2 {
|
||||
if n2 != nil {
|
||||
t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if ok1 && !isNormalized(n1) {
|
||||
t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
|
||||
}
|
||||
if ok2 && !isNormalized(n2) {
|
||||
t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
|
||||
}
|
||||
|
||||
if n1.Cmp(expected) != 0 {
|
||||
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
|
||||
}
|
||||
if n2.Cmp(expected) != 0 {
|
||||
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var formatTests = []struct {
|
||||
input string
|
||||
format string
|
||||
output string
|
||||
}{
|
||||
{"<nil>", "%x", "<nil>"},
|
||||
{"<nil>", "%#x", "<nil>"},
|
||||
{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
|
||||
|
||||
{"10", "%b", "1010"},
|
||||
{"10", "%o", "12"},
|
||||
{"10", "%d", "10"},
|
||||
{"10", "%v", "10"},
|
||||
{"10", "%x", "a"},
|
||||
{"10", "%X", "A"},
|
||||
{"-10", "%X", "-A"},
|
||||
{"10", "%y", "%!y(big.Int=10)"},
|
||||
{"-10", "%y", "%!y(big.Int=-10)"},
|
||||
|
||||
{"10", "%#b", "1010"},
|
||||
{"10", "%#o", "012"},
|
||||
{"10", "%#d", "10"},
|
||||
{"10", "%#v", "10"},
|
||||
{"10", "%#x", "0xa"},
|
||||
{"10", "%#X", "0XA"},
|
||||
{"-10", "%#X", "-0XA"},
|
||||
{"10", "%#y", "%!y(big.Int=10)"},
|
||||
{"-10", "%#y", "%!y(big.Int=-10)"},
|
||||
|
||||
{"1234", "%d", "1234"},
|
||||
{"1234", "%3d", "1234"},
|
||||
{"1234", "%4d", "1234"},
|
||||
{"-1234", "%d", "-1234"},
|
||||
{"1234", "% 5d", " 1234"},
|
||||
{"1234", "%+5d", "+1234"},
|
||||
{"1234", "%-5d", "1234 "},
|
||||
{"1234", "%x", "4d2"},
|
||||
{"1234", "%X", "4D2"},
|
||||
{"-1234", "%3x", "-4d2"},
|
||||
{"-1234", "%4x", "-4d2"},
|
||||
{"-1234", "%5x", " -4d2"},
|
||||
{"-1234", "%-5x", "-4d2 "},
|
||||
{"1234", "%03d", "1234"},
|
||||
{"1234", "%04d", "1234"},
|
||||
{"1234", "%05d", "01234"},
|
||||
{"1234", "%06d", "001234"},
|
||||
{"-1234", "%06d", "-01234"},
|
||||
{"1234", "%+06d", "+01234"},
|
||||
{"1234", "% 06d", " 01234"},
|
||||
{"1234", "%-6d", "1234 "},
|
||||
{"1234", "%-06d", "1234 "},
|
||||
{"-1234", "%-06d", "-1234 "},
|
||||
|
||||
{"1234", "%.3d", "1234"},
|
||||
{"1234", "%.4d", "1234"},
|
||||
{"1234", "%.5d", "01234"},
|
||||
{"1234", "%.6d", "001234"},
|
||||
{"-1234", "%.3d", "-1234"},
|
||||
{"-1234", "%.4d", "-1234"},
|
||||
{"-1234", "%.5d", "-01234"},
|
||||
{"-1234", "%.6d", "-001234"},
|
||||
|
||||
{"1234", "%8.3d", " 1234"},
|
||||
{"1234", "%8.4d", " 1234"},
|
||||
{"1234", "%8.5d", " 01234"},
|
||||
{"1234", "%8.6d", " 001234"},
|
||||
{"-1234", "%8.3d", " -1234"},
|
||||
{"-1234", "%8.4d", " -1234"},
|
||||
{"-1234", "%8.5d", " -01234"},
|
||||
{"-1234", "%8.6d", " -001234"},
|
||||
|
||||
{"1234", "%+8.3d", " +1234"},
|
||||
{"1234", "%+8.4d", " +1234"},
|
||||
{"1234", "%+8.5d", " +01234"},
|
||||
{"1234", "%+8.6d", " +001234"},
|
||||
{"-1234", "%+8.3d", " -1234"},
|
||||
{"-1234", "%+8.4d", " -1234"},
|
||||
{"-1234", "%+8.5d", " -01234"},
|
||||
{"-1234", "%+8.6d", " -001234"},
|
||||
|
||||
{"1234", "% 8.3d", " 1234"},
|
||||
{"1234", "% 8.4d", " 1234"},
|
||||
{"1234", "% 8.5d", " 01234"},
|
||||
{"1234", "% 8.6d", " 001234"},
|
||||
{"-1234", "% 8.3d", " -1234"},
|
||||
{"-1234", "% 8.4d", " -1234"},
|
||||
{"-1234", "% 8.5d", " -01234"},
|
||||
{"-1234", "% 8.6d", " -001234"},
|
||||
|
||||
{"1234", "%.3x", "4d2"},
|
||||
{"1234", "%.4x", "04d2"},
|
||||
{"1234", "%.5x", "004d2"},
|
||||
{"1234", "%.6x", "0004d2"},
|
||||
{"-1234", "%.3x", "-4d2"},
|
||||
{"-1234", "%.4x", "-04d2"},
|
||||
{"-1234", "%.5x", "-004d2"},
|
||||
{"-1234", "%.6x", "-0004d2"},
|
||||
|
||||
{"1234", "%8.3x", " 4d2"},
|
||||
{"1234", "%8.4x", " 04d2"},
|
||||
{"1234", "%8.5x", " 004d2"},
|
||||
{"1234", "%8.6x", " 0004d2"},
|
||||
{"-1234", "%8.3x", " -4d2"},
|
||||
{"-1234", "%8.4x", " -04d2"},
|
||||
{"-1234", "%8.5x", " -004d2"},
|
||||
{"-1234", "%8.6x", " -0004d2"},
|
||||
|
||||
{"1234", "%+8.3x", " +4d2"},
|
||||
{"1234", "%+8.4x", " +04d2"},
|
||||
{"1234", "%+8.5x", " +004d2"},
|
||||
{"1234", "%+8.6x", " +0004d2"},
|
||||
{"-1234", "%+8.3x", " -4d2"},
|
||||
{"-1234", "%+8.4x", " -04d2"},
|
||||
{"-1234", "%+8.5x", " -004d2"},
|
||||
{"-1234", "%+8.6x", " -0004d2"},
|
||||
|
||||
{"1234", "% 8.3x", " 4d2"},
|
||||
{"1234", "% 8.4x", " 04d2"},
|
||||
{"1234", "% 8.5x", " 004d2"},
|
||||
{"1234", "% 8.6x", " 0004d2"},
|
||||
{"1234", "% 8.7x", " 00004d2"},
|
||||
{"1234", "% 8.8x", " 000004d2"},
|
||||
{"-1234", "% 8.3x", " -4d2"},
|
||||
{"-1234", "% 8.4x", " -04d2"},
|
||||
{"-1234", "% 8.5x", " -004d2"},
|
||||
{"-1234", "% 8.6x", " -0004d2"},
|
||||
{"-1234", "% 8.7x", "-00004d2"},
|
||||
{"-1234", "% 8.8x", "-000004d2"},
|
||||
|
||||
{"1234", "%-8.3d", "1234 "},
|
||||
{"1234", "%-8.4d", "1234 "},
|
||||
{"1234", "%-8.5d", "01234 "},
|
||||
{"1234", "%-8.6d", "001234 "},
|
||||
{"1234", "%-8.7d", "0001234 "},
|
||||
{"1234", "%-8.8d", "00001234"},
|
||||
{"-1234", "%-8.3d", "-1234 "},
|
||||
{"-1234", "%-8.4d", "-1234 "},
|
||||
{"-1234", "%-8.5d", "-01234 "},
|
||||
{"-1234", "%-8.6d", "-001234 "},
|
||||
{"-1234", "%-8.7d", "-0001234"},
|
||||
{"-1234", "%-8.8d", "-00001234"},
|
||||
|
||||
{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
|
||||
|
||||
{"0", "%.d", ""},
|
||||
{"0", "%.0d", ""},
|
||||
{"0", "%3.d", ""},
|
||||
}
|
||||
|
||||
func TestFormat(t *testing.T) {
|
||||
for i, test := range formatTests {
|
||||
var x *Int
|
||||
if test.input != "<nil>" {
|
||||
var ok bool
|
||||
x, ok = new(Int).SetString(test.input, 0)
|
||||
if !ok {
|
||||
t.Errorf("#%d failed reading input %s", i, test.input)
|
||||
}
|
||||
}
|
||||
output := fmt.Sprintf(test.format, x)
|
||||
if output != test.output {
|
||||
t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var scanTests = []struct {
|
||||
input string
|
||||
format string
|
||||
output string
|
||||
remaining int
|
||||
}{
|
||||
{"1010", "%b", "10", 0},
|
||||
{"0b1010", "%v", "10", 0},
|
||||
{"12", "%o", "10", 0},
|
||||
{"012", "%v", "10", 0},
|
||||
{"10", "%d", "10", 0},
|
||||
{"10", "%v", "10", 0},
|
||||
{"a", "%x", "10", 0},
|
||||
{"0xa", "%v", "10", 0},
|
||||
{"A", "%X", "10", 0},
|
||||
{"-A", "%X", "-10", 0},
|
||||
{"+0b1011001", "%v", "89", 0},
|
||||
{"0xA", "%v", "10", 0},
|
||||
{"0 ", "%v", "0", 1},
|
||||
{"2+3", "%v", "2", 2},
|
||||
{"0XABC 12", "%v", "2748", 3},
|
||||
}
|
||||
|
||||
func TestScan(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
for i, test := range scanTests {
|
||||
x := new(Int)
|
||||
buf.Reset()
|
||||
buf.WriteString(test.input)
|
||||
if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
|
||||
t.Errorf("#%d error: %s", i, err)
|
||||
}
|
||||
if x.String() != test.output {
|
||||
t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
|
||||
}
|
||||
if buf.Len() != test.remaining {
|
||||
t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,518 @@
|
|||
// 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 big
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var cmpTests = []struct {
|
||||
x, y nat
|
||||
r int
|
||||
}{
|
||||
{nil, nil, 0},
|
||||
{nil, nat(nil), 0},
|
||||
{nat(nil), nil, 0},
|
||||
{nat(nil), nat(nil), 0},
|
||||
{nat{0}, nat{0}, 0},
|
||||
{nat{0}, nat{1}, -1},
|
||||
{nat{1}, nat{0}, 1},
|
||||
{nat{1}, nat{1}, 0},
|
||||
{nat{0, _M}, nat{1}, 1},
|
||||
{nat{1}, nat{0, _M}, -1},
|
||||
{nat{1, _M}, nat{0, _M}, 1},
|
||||
{nat{0, _M}, nat{1, _M}, -1},
|
||||
{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
|
||||
{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
|
||||
}
|
||||
|
||||
func TestCmp(t *testing.T) {
|
||||
for i, a := range cmpTests {
|
||||
r := a.x.cmp(a.y)
|
||||
if r != a.r {
|
||||
t.Errorf("#%d got r = %v; want %v", i, r, a.r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type funNN func(z, x, y nat) nat
|
||||
type argNN struct {
|
||||
z, x, y nat
|
||||
}
|
||||
|
||||
var sumNN = []argNN{
|
||||
{},
|
||||
{nat{1}, nil, nat{1}},
|
||||
{nat{1111111110}, nat{123456789}, nat{987654321}},
|
||||
{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
|
||||
{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
|
||||
{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
|
||||
}
|
||||
|
||||
var prodNN = []argNN{
|
||||
{},
|
||||
{nil, nil, nil},
|
||||
{nil, nat{991}, nil},
|
||||
{nat{991}, nat{991}, nat{1}},
|
||||
{nat{991 * 991}, nat{991}, nat{991}},
|
||||
{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
|
||||
{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
|
||||
{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
|
||||
// 3^100 * 3^28 = 3^128
|
||||
{
|
||||
natFromString("11790184577738583171520872861412518665678211592275841109096961"),
|
||||
natFromString("515377520732011331036461129765621272702107522001"),
|
||||
natFromString("22876792454961"),
|
||||
},
|
||||
// z = 111....1 (70000 digits)
|
||||
// x = 10^(99*700) + ... + 10^1400 + 10^700 + 1
|
||||
// y = 111....1 (700 digits, larger than Karatsuba threshold on 32-bit and 64-bit)
|
||||
{
|
||||
natFromString(strings.Repeat("1", 70000)),
|
||||
natFromString("1" + strings.Repeat(strings.Repeat("0", 699)+"1", 99)),
|
||||
natFromString(strings.Repeat("1", 700)),
|
||||
},
|
||||
// z = 111....1 (20000 digits)
|
||||
// x = 10^10000 + 1
|
||||
// y = 111....1 (10000 digits)
|
||||
{
|
||||
natFromString(strings.Repeat("1", 20000)),
|
||||
natFromString("1" + strings.Repeat("0", 9999) + "1"),
|
||||
natFromString(strings.Repeat("1", 10000)),
|
||||
},
|
||||
}
|
||||
|
||||
func natFromString(s string) nat {
|
||||
x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
for _, a := range sumNN {
|
||||
z := nat(nil).set(a.z)
|
||||
if z.cmp(a.z) != 0 {
|
||||
t.Errorf("got z = %v; want %v", z, a.z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
|
||||
z := f(nil, a.x, a.y)
|
||||
if z.cmp(a.z) != 0 {
|
||||
t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunNN(t *testing.T) {
|
||||
for _, a := range sumNN {
|
||||
arg := a
|
||||
testFunNN(t, "add", nat.add, arg)
|
||||
|
||||
arg = argNN{a.z, a.y, a.x}
|
||||
testFunNN(t, "add symmetric", nat.add, arg)
|
||||
|
||||
arg = argNN{a.x, a.z, a.y}
|
||||
testFunNN(t, "sub", nat.sub, arg)
|
||||
|
||||
arg = argNN{a.y, a.z, a.x}
|
||||
testFunNN(t, "sub symmetric", nat.sub, arg)
|
||||
}
|
||||
|
||||
for _, a := range prodNN {
|
||||
arg := a
|
||||
testFunNN(t, "mul", nat.mul, arg)
|
||||
|
||||
arg = argNN{a.z, a.y, a.x}
|
||||
testFunNN(t, "mul symmetric", nat.mul, arg)
|
||||
}
|
||||
}
|
||||
|
||||
var mulRangesN = []struct {
|
||||
a, b uint64
|
||||
prod string
|
||||
}{
|
||||
{0, 0, "0"},
|
||||
{1, 1, "1"},
|
||||
{1, 2, "2"},
|
||||
{1, 3, "6"},
|
||||
{10, 10, "10"},
|
||||
{0, 100, "0"},
|
||||
{0, 1e9, "0"},
|
||||
{1, 0, "1"}, // empty range
|
||||
{100, 1, "1"}, // empty range
|
||||
{1, 10, "3628800"}, // 10!
|
||||
{1, 20, "2432902008176640000"}, // 20!
|
||||
{1, 100,
|
||||
"933262154439441526816992388562667004907159682643816214685929" +
|
||||
"638952175999932299156089414639761565182862536979208272237582" +
|
||||
"51185210916864000000000000000000000000", // 100!
|
||||
},
|
||||
}
|
||||
|
||||
func TestMulRangeN(t *testing.T) {
|
||||
for i, r := range mulRangesN {
|
||||
prod := nat(nil).mulRange(r.a, r.b).decimalString()
|
||||
if prod != r.prod {
|
||||
t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocBytes returns the number of bytes allocated by invoking f.
|
||||
func allocBytes(f func()) uint64 {
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
t := stats.TotalAlloc
|
||||
f()
|
||||
runtime.ReadMemStats(&stats)
|
||||
return stats.TotalAlloc - t
|
||||
}
|
||||
|
||||
// TestMulUnbalanced tests that multiplying numbers of different lengths
|
||||
// does not cause deep recursion and in turn allocate too much memory.
|
||||
// Test case for issue 3807.
|
||||
func TestMulUnbalanced(t *testing.T) {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
|
||||
x := rndNat(50000)
|
||||
y := rndNat(40)
|
||||
allocSize := allocBytes(func() {
|
||||
nat(nil).mul(x, y)
|
||||
})
|
||||
inputSize := uint64(len(x)+len(y)) * _S
|
||||
if ratio := allocSize / uint64(inputSize); ratio > 10 {
|
||||
t.Errorf("multiplication uses too much memory (%d > %d times the size of inputs)", allocSize, ratio)
|
||||
}
|
||||
}
|
||||
|
||||
func rndNat(n int) nat {
|
||||
return nat(rndV(n)).norm()
|
||||
}
|
||||
|
||||
func BenchmarkMul(b *testing.B) {
|
||||
mulx := rndNat(1e4)
|
||||
muly := rndNat(1e4)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var z nat
|
||||
z.mul(mulx, muly)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLeadingZeros(t *testing.T) {
|
||||
var x Word = _B >> 1
|
||||
for i := 0; i <= _W; i++ {
|
||||
if int(leadingZeros(x)) != i {
|
||||
t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
|
||||
}
|
||||
x >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
type shiftTest struct {
|
||||
in nat
|
||||
shift uint
|
||||
out nat
|
||||
}
|
||||
|
||||
var leftShiftTests = []shiftTest{
|
||||
{nil, 0, nil},
|
||||
{nil, 1, nil},
|
||||
{natOne, 0, natOne},
|
||||
{natOne, 1, natTwo},
|
||||
{nat{1 << (_W - 1)}, 1, nat{0}},
|
||||
{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
|
||||
}
|
||||
|
||||
func TestShiftLeft(t *testing.T) {
|
||||
for i, test := range leftShiftTests {
|
||||
var z nat
|
||||
z = z.shl(test.in, test.shift)
|
||||
for j, d := range test.out {
|
||||
if j >= len(z) || z[j] != d {
|
||||
t.Errorf("#%d: got: %v want: %v", i, z, test.out)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rightShiftTests = []shiftTest{
|
||||
{nil, 0, nil},
|
||||
{nil, 1, nil},
|
||||
{natOne, 0, natOne},
|
||||
{natOne, 1, nil},
|
||||
{natTwo, 1, natOne},
|
||||
{nat{0, 1}, 1, nat{1 << (_W - 1)}},
|
||||
{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
|
||||
}
|
||||
|
||||
func TestShiftRight(t *testing.T) {
|
||||
for i, test := range rightShiftTests {
|
||||
var z nat
|
||||
z = z.shr(test.in, test.shift)
|
||||
for j, d := range test.out {
|
||||
if j >= len(z) || z[j] != d {
|
||||
t.Errorf("#%d: got: %v want: %v", i, z, test.out)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type modWTest struct {
|
||||
in string
|
||||
dividend string
|
||||
out string
|
||||
}
|
||||
|
||||
var modWTests32 = []modWTest{
|
||||
{"23492635982634928349238759823742", "252341", "220170"},
|
||||
}
|
||||
|
||||
var modWTests64 = []modWTest{
|
||||
{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
|
||||
}
|
||||
|
||||
func runModWTests(t *testing.T, tests []modWTest) {
|
||||
for i, test := range tests {
|
||||
in, _ := new(Int).SetString(test.in, 10)
|
||||
d, _ := new(Int).SetString(test.dividend, 10)
|
||||
out, _ := new(Int).SetString(test.out, 10)
|
||||
|
||||
r := in.abs.modW(d.abs[0])
|
||||
if r != out.abs[0] {
|
||||
t.Errorf("#%d failed: got %d want %s", i, r, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestModW(t *testing.T) {
|
||||
if _W >= 32 {
|
||||
runModWTests(t, modWTests32)
|
||||
}
|
||||
if _W >= 64 {
|
||||
runModWTests(t, modWTests64)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrailingZeroBits(t *testing.T) {
|
||||
// test 0 case explicitly
|
||||
if n := trailingZeroBits(0); n != 0 {
|
||||
t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
|
||||
}
|
||||
|
||||
x := Word(1)
|
||||
for i := uint(0); i < _W; i++ {
|
||||
n := trailingZeroBits(x)
|
||||
if n != i {
|
||||
t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
|
||||
}
|
||||
x <<= 1
|
||||
}
|
||||
|
||||
// test 0 case explicitly
|
||||
if n := nat(nil).trailingZeroBits(); n != 0 {
|
||||
t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
|
||||
}
|
||||
|
||||
y := nat(nil).set(natOne)
|
||||
for i := uint(0); i <= 3*_W; i++ {
|
||||
n := y.trailingZeroBits()
|
||||
if n != i {
|
||||
t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
|
||||
}
|
||||
y = y.shl(y, 1)
|
||||
}
|
||||
}
|
||||
|
||||
var expNNTests = []struct {
|
||||
x, y, m string
|
||||
out string
|
||||
}{
|
||||
{"0", "0", "0", "1"},
|
||||
{"0", "0", "1", "0"},
|
||||
{"1", "1", "1", "0"},
|
||||
{"2", "1", "1", "0"},
|
||||
{"2", "2", "1", "0"},
|
||||
{"10", "100000000000", "1", "0"},
|
||||
{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
|
||||
{"0x8000000000000000", "2", "6719", "4944"},
|
||||
{"0x8000000000000000", "3", "6719", "5447"},
|
||||
{"0x8000000000000000", "1000", "6719", "1603"},
|
||||
{"0x8000000000000000", "1000000", "6719", "3199"},
|
||||
{
|
||||
"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
|
||||
"298472983472983471903246121093472394872319615612417471234712061",
|
||||
"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
|
||||
"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
|
||||
},
|
||||
}
|
||||
|
||||
func TestExpNN(t *testing.T) {
|
||||
for i, test := range expNNTests {
|
||||
x := natFromString(test.x)
|
||||
y := natFromString(test.y)
|
||||
out := natFromString(test.out)
|
||||
|
||||
var m nat
|
||||
if len(test.m) > 0 {
|
||||
m = natFromString(test.m)
|
||||
}
|
||||
|
||||
z := nat(nil).expNN(x, y, m)
|
||||
if z.cmp(out) != 0 {
|
||||
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExpHelper(b *testing.B, x, y Word) {
|
||||
var z nat
|
||||
for i := 0; i < b.N; i++ {
|
||||
z.expWW(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExp3Power0x10(b *testing.B) { ExpHelper(b, 3, 0x10) }
|
||||
func BenchmarkExp3Power0x40(b *testing.B) { ExpHelper(b, 3, 0x40) }
|
||||
func BenchmarkExp3Power0x100(b *testing.B) { ExpHelper(b, 3, 0x100) }
|
||||
func BenchmarkExp3Power0x400(b *testing.B) { ExpHelper(b, 3, 0x400) }
|
||||
func BenchmarkExp3Power0x1000(b *testing.B) { ExpHelper(b, 3, 0x1000) }
|
||||
func BenchmarkExp3Power0x4000(b *testing.B) { ExpHelper(b, 3, 0x4000) }
|
||||
func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
|
||||
func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
|
||||
func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
|
||||
func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
|
||||
|
||||
func fibo(n int) nat {
|
||||
switch n {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return nat{1}
|
||||
}
|
||||
f0 := fibo(0)
|
||||
f1 := fibo(1)
|
||||
var f2 nat
|
||||
for i := 1; i < n; i++ {
|
||||
f2 = f2.add(f0, f1)
|
||||
f0, f1, f2 = f1, f2, f0
|
||||
}
|
||||
return f1
|
||||
}
|
||||
|
||||
var fiboNums = []string{
|
||||
"0",
|
||||
"55",
|
||||
"6765",
|
||||
"832040",
|
||||
"102334155",
|
||||
"12586269025",
|
||||
"1548008755920",
|
||||
"190392490709135",
|
||||
"23416728348467685",
|
||||
"2880067194370816120",
|
||||
"354224848179261915075",
|
||||
}
|
||||
|
||||
func TestFibo(t *testing.T) {
|
||||
for i, want := range fiboNums {
|
||||
n := i * 10
|
||||
got := fibo(n).decimalString()
|
||||
if got != want {
|
||||
t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFibo(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
fibo(1e0)
|
||||
fibo(1e1)
|
||||
fibo(1e2)
|
||||
fibo(1e3)
|
||||
fibo(1e4)
|
||||
fibo(1e5)
|
||||
}
|
||||
}
|
||||
|
||||
var bitTests = []struct {
|
||||
x string
|
||||
i uint
|
||||
want uint
|
||||
}{
|
||||
{"0", 0, 0},
|
||||
{"0", 1, 0},
|
||||
{"0", 1000, 0},
|
||||
|
||||
{"0x1", 0, 1},
|
||||
{"0x10", 0, 0},
|
||||
{"0x10", 3, 0},
|
||||
{"0x10", 4, 1},
|
||||
{"0x10", 5, 0},
|
||||
|
||||
{"0x8000000000000000", 62, 0},
|
||||
{"0x8000000000000000", 63, 1},
|
||||
{"0x8000000000000000", 64, 0},
|
||||
|
||||
{"0x3" + strings.Repeat("0", 32), 127, 0},
|
||||
{"0x3" + strings.Repeat("0", 32), 128, 1},
|
||||
{"0x3" + strings.Repeat("0", 32), 129, 1},
|
||||
{"0x3" + strings.Repeat("0", 32), 130, 0},
|
||||
}
|
||||
|
||||
func TestBit(t *testing.T) {
|
||||
for i, test := range bitTests {
|
||||
x := natFromString(test.x)
|
||||
if got := x.bit(test.i); got != test.want {
|
||||
t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stickyTests = []struct {
|
||||
x string
|
||||
i uint
|
||||
want uint
|
||||
}{
|
||||
{"0", 0, 0},
|
||||
{"0", 1, 0},
|
||||
{"0", 1000, 0},
|
||||
|
||||
{"0x1", 0, 0},
|
||||
{"0x1", 1, 1},
|
||||
|
||||
{"0x1350", 0, 0},
|
||||
{"0x1350", 4, 0},
|
||||
{"0x1350", 5, 1},
|
||||
|
||||
{"0x8000000000000000", 63, 0},
|
||||
{"0x8000000000000000", 64, 1},
|
||||
|
||||
{"0x1" + strings.Repeat("0", 100), 400, 0},
|
||||
{"0x1" + strings.Repeat("0", 100), 401, 1},
|
||||
}
|
||||
|
||||
func TestSticky(t *testing.T) {
|
||||
for i, test := range stickyTests {
|
||||
x := natFromString(test.x)
|
||||
if got := x.sticky(test.i); got != test.want {
|
||||
t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
|
||||
}
|
||||
if test.want == 1 {
|
||||
// all subsequent i's should also return 1
|
||||
for d := uint(1); d <= 3; d++ {
|
||||
if got := x.sticky(test.i + d); got != 1 {
|
||||
t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
// Copyright 2015 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 nat-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MaxBase is the largest number base accepted for string conversions.
|
||||
const MaxBase = 'z' - 'a' + 10 + 1
|
||||
|
||||
// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
|
||||
// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
|
||||
// In other words, at most n digits in base b fit into a Word.
|
||||
// TODO(gri) replace this with a table, generated at build time.
|
||||
func maxPow(b Word) (p Word, n int) {
|
||||
p, n = b, 1 // assuming b <= _M
|
||||
for max := _M / b; p <= max; {
|
||||
// p == b**n && p <= max
|
||||
p *= b
|
||||
n++
|
||||
}
|
||||
// p == b**n && p <= _M
|
||||
return
|
||||
}
|
||||
|
||||
// pow returns x**n for n > 0, and 1 otherwise.
|
||||
func pow(x Word, n int) (p Word) {
|
||||
// n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
|
||||
// thus x**n == product of x**(2**i) for all i where bi == 1
|
||||
// (Russian Peasant Method for exponentiation)
|
||||
p = 1
|
||||
for n > 0 {
|
||||
if n&1 != 0 {
|
||||
p *= x
|
||||
}
|
||||
x *= x
|
||||
n >>= 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// scan scans the number corresponding to the longest possible prefix
|
||||
// from r representing an unsigned number in a given conversion base.
|
||||
// It returns the corresponding natural number res, the actual base b,
|
||||
// a digit count, and a read or syntax error err, if any.
|
||||
//
|
||||
// number = [ prefix ] mantissa .
|
||||
// prefix = "0" [ "x" | "X" | "b" | "B" ] .
|
||||
// mantissa = digits | digits "." [ digits ] | "." digits .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
|
||||
//
|
||||
// Unless fracOk is set, the base argument must be 0 or a value between
|
||||
// 2 and MaxBase. If fracOk is set, the base argument must be one of
|
||||
// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
|
||||
// time panic.
|
||||
//
|
||||
// For base 0, the number prefix determines the actual base: A prefix of
|
||||
// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
|
||||
// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
|
||||
// the selected base is 10 and no prefix is accepted.
|
||||
//
|
||||
// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
|
||||
// stands for a zero digit), and a period followed by a fractional part
|
||||
// is permitted. The result value is computed as if there were no period
|
||||
// present; and the count value is used to determine the fractional part.
|
||||
//
|
||||
// A result digit count > 0 corresponds to the number of (non-prefix) digits
|
||||
// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
|
||||
// is set, only), and -count is the number of fractional digits found.
|
||||
// In this case, the actual value of the scanned number is res * b**count.
|
||||
//
|
||||
func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
|
||||
// reject illegal bases
|
||||
baseOk := base == 0 ||
|
||||
!fracOk && 2 <= base && base <= MaxBase ||
|
||||
fracOk && (base == 2 || base == 10 || base == 16)
|
||||
if !baseOk {
|
||||
panic(fmt.Sprintf("illegal number base %d", base))
|
||||
}
|
||||
|
||||
// one char look-ahead
|
||||
ch, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// determine actual base
|
||||
b = base
|
||||
if base == 0 {
|
||||
// actual base is 10 unless there's a base prefix
|
||||
b = 10
|
||||
if ch == '0' {
|
||||
count = 1
|
||||
switch ch, err = r.ReadByte(); err {
|
||||
case nil:
|
||||
// possibly one of 0x, 0X, 0b, 0B
|
||||
if !fracOk {
|
||||
b = 8
|
||||
}
|
||||
switch ch {
|
||||
case 'x', 'X':
|
||||
b = 16
|
||||
case 'b', 'B':
|
||||
b = 2
|
||||
}
|
||||
switch b {
|
||||
case 16, 2:
|
||||
count = 0 // prefix is not counted
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
// io.EOF is also an error in this case
|
||||
return
|
||||
}
|
||||
case 8:
|
||||
count = 0 // prefix is not counted
|
||||
}
|
||||
case io.EOF:
|
||||
// input is "0"
|
||||
res = z[:0]
|
||||
err = nil
|
||||
return
|
||||
default:
|
||||
// read error
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert string
|
||||
// Algorithm: Collect digits in groups of at most n digits in di
|
||||
// and then use mulAddWW for every such group to add them to the
|
||||
// result.
|
||||
z = z[:0]
|
||||
b1 := Word(b)
|
||||
bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
|
||||
di := Word(0) // 0 <= di < b1**i < bn
|
||||
i := 0 // 0 <= i < n
|
||||
dp := -1 // position of decimal point
|
||||
for {
|
||||
if fracOk && ch == '.' {
|
||||
fracOk = false
|
||||
dp = count
|
||||
// advance
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// convert rune into digit value d1
|
||||
var d1 Word
|
||||
switch {
|
||||
case '0' <= ch && ch <= '9':
|
||||
d1 = Word(ch - '0')
|
||||
case 'a' <= ch && ch <= 'z':
|
||||
d1 = Word(ch - 'a' + 10)
|
||||
case 'A' <= ch && ch <= 'Z':
|
||||
d1 = Word(ch - 'A' + 10)
|
||||
default:
|
||||
d1 = MaxBase + 1
|
||||
}
|
||||
if d1 >= b1 {
|
||||
r.UnreadByte() // ch does not belong to number anymore
|
||||
break
|
||||
}
|
||||
count++
|
||||
|
||||
// collect d1 in di
|
||||
di = di*b1 + d1
|
||||
i++
|
||||
|
||||
// if di is "full", add it to the result
|
||||
if i == n {
|
||||
z = z.mulAddWW(z, bn, di)
|
||||
di = 0
|
||||
i = 0
|
||||
}
|
||||
|
||||
// advance
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
// no digits found
|
||||
switch {
|
||||
case base == 0 && b == 8:
|
||||
// there was only the octal prefix 0 (possibly followed by digits > 7);
|
||||
// count as one digit and return base 10, not 8
|
||||
count = 1
|
||||
b = 10
|
||||
case base != 0 || b != 8:
|
||||
// there was neither a mantissa digit nor the octal prefix 0
|
||||
err = errors.New("syntax error scanning number")
|
||||
}
|
||||
return
|
||||
}
|
||||
// count > 0
|
||||
|
||||
// add remaining digits to result
|
||||
if i > 0 {
|
||||
z = z.mulAddWW(z, pow(b1, i), di)
|
||||
}
|
||||
res = z.norm()
|
||||
|
||||
// adjust for fraction, if any
|
||||
if dp >= 0 {
|
||||
// 0 <= dp <= count > 0
|
||||
count = dp - count
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Character sets for string conversion.
|
||||
const (
|
||||
lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
// decimalString returns a decimal representation of x.
|
||||
// It calls x.string with the charset "0123456789".
|
||||
func (x nat) decimalString() string {
|
||||
return x.string(lowercaseDigits[:10])
|
||||
}
|
||||
|
||||
// hexString returns a hexadecimal representation of x.
|
||||
// It calls x.string with the charset "0123456789abcdef".
|
||||
func (x nat) hexString() string {
|
||||
return x.string(lowercaseDigits[:16])
|
||||
}
|
||||
|
||||
// string converts x to a string using digits from a charset; a digit with
|
||||
// value d is represented by charset[d]. The conversion base is determined
|
||||
// by len(charset), which must be >= 2 and <= 256.
|
||||
func (x nat) string(charset string) string {
|
||||
b := Word(len(charset))
|
||||
|
||||
// special cases
|
||||
switch {
|
||||
case b < 2 || b > 256:
|
||||
panic("invalid character set length")
|
||||
case len(x) == 0:
|
||||
return string(charset[0])
|
||||
}
|
||||
|
||||
// allocate buffer for conversion
|
||||
i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
|
||||
s := make([]byte, i)
|
||||
|
||||
// convert power of two and non power of two bases separately
|
||||
if b == b&-b {
|
||||
// shift is base-b digit size in bits
|
||||
shift := trailingZeroBits(b) // shift > 0 because b >= 2
|
||||
mask := Word(1)<<shift - 1
|
||||
w := x[0]
|
||||
nbits := uint(_W) // number of unprocessed bits in w
|
||||
|
||||
// convert less-significant words
|
||||
for k := 1; k < len(x); k++ {
|
||||
// convert full digits
|
||||
for nbits >= shift {
|
||||
i--
|
||||
s[i] = charset[w&mask]
|
||||
w >>= shift
|
||||
nbits -= shift
|
||||
}
|
||||
|
||||
// convert any partial leading digit and advance to next word
|
||||
if nbits == 0 {
|
||||
// no partial digit remaining, just advance
|
||||
w = x[k]
|
||||
nbits = _W
|
||||
} else {
|
||||
// partial digit in current (k-1) and next (k) word
|
||||
w |= x[k] << nbits
|
||||
i--
|
||||
s[i] = charset[w&mask]
|
||||
|
||||
// advance
|
||||
w = x[k] >> (shift - nbits)
|
||||
nbits = _W - (shift - nbits)
|
||||
}
|
||||
}
|
||||
|
||||
// convert digits of most-significant word (omit leading zeros)
|
||||
for nbits >= 0 && w != 0 {
|
||||
i--
|
||||
s[i] = charset[w&mask]
|
||||
w >>= shift
|
||||
nbits -= shift
|
||||
}
|
||||
|
||||
} else {
|
||||
bb, ndigits := maxPow(Word(b))
|
||||
|
||||
// construct table of successive squares of bb*leafSize to use in subdivisions
|
||||
// result (table != nil) <=> (len(x) > leafSize > 0)
|
||||
table := divisors(len(x), b, ndigits, bb)
|
||||
|
||||
// preserve x, create local copy for use by convertWords
|
||||
q := nat(nil).set(x)
|
||||
|
||||
// convert q to string s in base b
|
||||
q.convertWords(s, charset, b, ndigits, bb, table)
|
||||
|
||||
// strip leading zeros
|
||||
// (x != 0; thus s must contain at least one non-zero digit
|
||||
// and the loop will terminate)
|
||||
i = 0
|
||||
for zero := charset[0]; s[i] == zero; {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return string(s[i:])
|
||||
}
|
||||
|
||||
// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
|
||||
// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
|
||||
// repeated nat/Word division.
|
||||
//
|
||||
// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
|
||||
// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
|
||||
// Recursive conversion divides q by its approximate square root, yielding two parts, each half
|
||||
// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
|
||||
// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
|
||||
// is made better by splitting the subblocks recursively. Best is to split blocks until one more
|
||||
// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
|
||||
// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
|
||||
// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
|
||||
// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
|
||||
// specific hardware.
|
||||
//
|
||||
func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
|
||||
// split larger blocks recursively
|
||||
if table != nil {
|
||||
// len(q) > leafSize > 0
|
||||
var r nat
|
||||
index := len(table) - 1
|
||||
for len(q) > leafSize {
|
||||
// find divisor close to sqrt(q) if possible, but in any case < q
|
||||
maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length
|
||||
minLength := maxLength >> 1 // ~= log2 sqrt(q)
|
||||
for index > 0 && table[index-1].nbits > minLength {
|
||||
index-- // desired
|
||||
}
|
||||
if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
|
||||
index--
|
||||
if index < 0 {
|
||||
panic("internal inconsistency")
|
||||
}
|
||||
}
|
||||
|
||||
// split q into the two digit number (q'*bbb + r) to form independent subblocks
|
||||
q, r = q.div(r, q, table[index].bbb)
|
||||
|
||||
// convert subblocks and collect results in s[:h] and s[h:]
|
||||
h := len(s) - table[index].ndigits
|
||||
r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
|
||||
s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
|
||||
}
|
||||
}
|
||||
|
||||
// having split any large blocks now process the remaining (small) block iteratively
|
||||
i := len(s)
|
||||
var r Word
|
||||
if b == 10 {
|
||||
// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
|
||||
for len(q) > 0 {
|
||||
// extract least significant, base bb "digit"
|
||||
q, r = q.divW(q, bb)
|
||||
for j := 0; j < ndigits && i > 0; j++ {
|
||||
i--
|
||||
// avoid % computation since r%10 == r - int(r/10)*10;
|
||||
// this appears to be faster for BenchmarkString10000Base10
|
||||
// and smaller strings (but a bit slower for larger ones)
|
||||
t := r / 10
|
||||
s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
|
||||
r = t
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for len(q) > 0 {
|
||||
// extract least significant, base bb "digit"
|
||||
q, r = q.divW(q, bb)
|
||||
for j := 0; j < ndigits && i > 0; j++ {
|
||||
i--
|
||||
s[i] = charset[r%b]
|
||||
r /= b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prepend high-order zeroes
|
||||
zero := charset[0]
|
||||
for i > 0 { // while need more leading zeroes
|
||||
i--
|
||||
s[i] = zero
|
||||
}
|
||||
}
|
||||
|
||||
// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
|
||||
// Benchmark and configure leafSize using: go test -bench="Leaf"
|
||||
// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
|
||||
// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
|
||||
var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
|
||||
|
||||
type divisor struct {
|
||||
bbb nat // divisor
|
||||
nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
|
||||
ndigits int // digit length of divisor in terms of output base digits
|
||||
}
|
||||
|
||||
var cacheBase10 struct {
|
||||
sync.Mutex
|
||||
table [64]divisor // cached divisors for base 10
|
||||
}
|
||||
|
||||
// expWW computes x**y
|
||||
func (z nat) expWW(x, y Word) nat {
|
||||
return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
|
||||
}
|
||||
|
||||
// construct table of powers of bb*leafSize to use in subdivisions
|
||||
func divisors(m int, b Word, ndigits int, bb Word) []divisor {
|
||||
// only compute table when recursive conversion is enabled and x is large
|
||||
if leafSize == 0 || m <= leafSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
|
||||
k := 1
|
||||
for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
|
||||
k++
|
||||
}
|
||||
|
||||
// reuse and extend existing table of divisors or create new table as appropriate
|
||||
var table []divisor // for b == 10, table overlaps with cacheBase10.table
|
||||
if b == 10 {
|
||||
cacheBase10.Lock()
|
||||
table = cacheBase10.table[0:k] // reuse old table for this conversion
|
||||
} else {
|
||||
table = make([]divisor, k) // create new table for this conversion
|
||||
}
|
||||
|
||||
// extend table
|
||||
if table[k-1].ndigits == 0 {
|
||||
// add new entries as needed
|
||||
var larger nat
|
||||
for i := 0; i < k; i++ {
|
||||
if table[i].ndigits == 0 {
|
||||
if i == 0 {
|
||||
table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
|
||||
table[0].ndigits = ndigits * leafSize
|
||||
} else {
|
||||
table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
|
||||
table[i].ndigits = 2 * table[i-1].ndigits
|
||||
}
|
||||
|
||||
// optimization: exploit aggregated extra bits in macro blocks
|
||||
larger = nat(nil).set(table[i].bbb)
|
||||
for mulAddVWW(larger, larger, b, 0) == 0 {
|
||||
table[i].bbb = table[i].bbb.set(larger)
|
||||
table[i].ndigits++
|
||||
}
|
||||
|
||||
table[i].nbits = table[i].bbb.bitLen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b == 10 {
|
||||
cacheBase10.Unlock()
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func toString(x nat, charset string) string {
|
||||
base := len(charset)
|
||||
|
||||
// special cases
|
||||
switch {
|
||||
case base < 2:
|
||||
panic("illegal base")
|
||||
case len(x) == 0:
|
||||
return string(charset[0])
|
||||
}
|
||||
|
||||
// allocate buffer for conversion
|
||||
i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
|
||||
s := make([]byte, i)
|
||||
|
||||
// don't destroy x
|
||||
q := nat(nil).set(x)
|
||||
|
||||
// convert
|
||||
for len(q) > 0 {
|
||||
i--
|
||||
var r Word
|
||||
q, r = q.divW(q, Word(base))
|
||||
s[i] = charset[r]
|
||||
}
|
||||
|
||||
return string(s[i:])
|
||||
}
|
||||
|
||||
var strTests = []struct {
|
||||
x nat // nat value to be converted
|
||||
c string // conversion charset
|
||||
s string // expected result
|
||||
}{
|
||||
{nil, "01", "0"},
|
||||
{nat{1}, "01", "1"},
|
||||
{nat{0xc5}, "01", "11000101"},
|
||||
{nat{03271}, lowercaseDigits[:8], "3271"},
|
||||
{nat{10}, lowercaseDigits[:10], "10"},
|
||||
{nat{1234567890}, uppercaseDigits[:10], "1234567890"},
|
||||
{nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
|
||||
{nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
|
||||
{nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
|
||||
{nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
// test invalid character set explicitly
|
||||
var panicStr string
|
||||
func() {
|
||||
defer func() {
|
||||
panicStr = recover().(string)
|
||||
}()
|
||||
natOne.string("0")
|
||||
}()
|
||||
if panicStr != "invalid character set length" {
|
||||
t.Errorf("expected panic for invalid character set")
|
||||
}
|
||||
|
||||
for _, a := range strTests {
|
||||
s := a.x.string(a.c)
|
||||
if s != a.s {
|
||||
t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
|
||||
}
|
||||
|
||||
x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
|
||||
if x.cmp(a.x) != 0 {
|
||||
t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
|
||||
}
|
||||
if b != len(a.c) {
|
||||
t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("scan%+v\n\tgot error = %s", a, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var natScanTests = []struct {
|
||||
s string // string to be scanned
|
||||
base int // input base
|
||||
frac bool // fraction ok
|
||||
x nat // expected nat
|
||||
b int // expected base
|
||||
count int // expected digit count
|
||||
ok bool // expected success
|
||||
next rune // next character (or 0, if at EOF)
|
||||
}{
|
||||
// error: no mantissa
|
||||
{},
|
||||
{s: "?"},
|
||||
{base: 10},
|
||||
{base: 36},
|
||||
{s: "?", base: 10},
|
||||
{s: "0x"},
|
||||
{s: "345", base: 2},
|
||||
|
||||
// error: incorrect use of decimal point
|
||||
{s: ".0"},
|
||||
{s: ".0", base: 10},
|
||||
{s: ".", base: 0},
|
||||
{s: "0x.0"},
|
||||
|
||||
// no errors
|
||||
{"0", 0, false, nil, 10, 1, true, 0},
|
||||
{"0", 10, false, nil, 10, 1, true, 0},
|
||||
{"0", 36, false, nil, 36, 1, true, 0},
|
||||
{"1", 0, false, nat{1}, 10, 1, true, 0},
|
||||
{"1", 10, false, nat{1}, 10, 1, true, 0},
|
||||
{"0 ", 0, false, nil, 10, 1, true, ' '},
|
||||
{"08", 0, false, nil, 10, 1, true, '8'},
|
||||
{"08", 10, false, nat{8}, 10, 2, true, 0},
|
||||
{"018", 0, false, nat{1}, 8, 1, true, '8'},
|
||||
{"0b1", 0, false, nat{1}, 2, 1, true, 0},
|
||||
{"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
|
||||
{"03271", 0, false, nat{03271}, 8, 4, true, 0},
|
||||
{"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
|
||||
{"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
|
||||
{"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
|
||||
{"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
|
||||
{"0x", 16, false, nil, 16, 1, true, 'x'},
|
||||
{"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
|
||||
{"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
|
||||
|
||||
// no errors, decimal point
|
||||
{"0.", 0, false, nil, 10, 1, true, '.'},
|
||||
{"0.", 10, true, nil, 10, 0, true, 0},
|
||||
{"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
|
||||
{".000", 10, true, nil, 10, -3, true, 0},
|
||||
{"12.3", 10, true, nat{123}, 10, -1, true, 0},
|
||||
{"012.345", 10, true, nat{12345}, 10, -3, true, 0},
|
||||
}
|
||||
|
||||
func TestScanBase(t *testing.T) {
|
||||
for _, a := range natScanTests {
|
||||
r := strings.NewReader(a.s)
|
||||
x, b, count, err := nat(nil).scan(r, a.base, a.frac)
|
||||
if err == nil && !a.ok {
|
||||
t.Errorf("scan%+v\n\texpected error", a)
|
||||
}
|
||||
if err != nil {
|
||||
if a.ok {
|
||||
t.Errorf("scan%+v\n\tgot error = %s", a, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if x.cmp(a.x) != 0 {
|
||||
t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
|
||||
}
|
||||
if b != a.b {
|
||||
t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
|
||||
}
|
||||
if count != a.count {
|
||||
t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
|
||||
}
|
||||
next, _, err := r.ReadRune()
|
||||
if err == io.EOF {
|
||||
next = 0
|
||||
err = nil
|
||||
}
|
||||
if err == nil && next != a.next {
|
||||
t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pi = "3" +
|
||||
"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
|
||||
"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
|
||||
"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
|
||||
"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
|
||||
"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
|
||||
"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
|
||||
"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
|
||||
"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
|
||||
"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
|
||||
"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
|
||||
"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
|
||||
"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
|
||||
"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
|
||||
"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
|
||||
"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
|
||||
"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
|
||||
"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
|
||||
"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
|
||||
"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
|
||||
"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
|
||||
"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
|
||||
"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
|
||||
"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
|
||||
"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
|
||||
"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
|
||||
"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
|
||||
"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
|
||||
"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
|
||||
"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
|
||||
"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
|
||||
"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
|
||||
"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
|
||||
"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
|
||||
"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
|
||||
"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
|
||||
"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
|
||||
"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
|
||||
"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
|
||||
"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
|
||||
"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
|
||||
"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
|
||||
"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
|
||||
"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
|
||||
"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
|
||||
"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
|
||||
"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
|
||||
"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
|
||||
"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
|
||||
"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
|
||||
"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
|
||||
"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
|
||||
|
||||
// Test case for BenchmarkScanPi.
|
||||
func TestScanPi(t *testing.T) {
|
||||
var x nat
|
||||
z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
|
||||
if err != nil {
|
||||
t.Errorf("scanning pi: %s", err)
|
||||
}
|
||||
if s := z.decimalString(); s != pi {
|
||||
t.Errorf("scanning pi: got %s", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanPiParallel(t *testing.T) {
|
||||
const n = 2
|
||||
c := make(chan int)
|
||||
for i := 0; i < n; i++ {
|
||||
go func() {
|
||||
TestScanPi(t)
|
||||
c <- 0
|
||||
}()
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
<-c
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScanPi(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
var x nat
|
||||
x.scan(strings.NewReader(pi), 10, false)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStringPiParallel(b *testing.B) {
|
||||
var x nat
|
||||
x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
|
||||
if x.decimalString() != pi {
|
||||
panic("benchmark incorrect: conversion failed")
|
||||
}
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
x.decimalString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
|
||||
func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) }
|
||||
func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) }
|
||||
func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) }
|
||||
func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
|
||||
|
||||
func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) }
|
||||
func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) }
|
||||
func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) }
|
||||
func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) }
|
||||
func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
|
||||
|
||||
func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) }
|
||||
func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) }
|
||||
func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) }
|
||||
func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) }
|
||||
func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
|
||||
|
||||
func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) }
|
||||
func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) }
|
||||
func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) }
|
||||
func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) }
|
||||
func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
|
||||
|
||||
func ScanHelper(b *testing.B, base int, x, y Word) {
|
||||
b.StopTimer()
|
||||
var z nat
|
||||
z = z.expWW(x, y)
|
||||
|
||||
var s string
|
||||
s = z.string(lowercaseDigits[:base])
|
||||
if t := toString(z, lowercaseDigits[:base]); t != s {
|
||||
b.Fatalf("scanning: got %s; want %s", s, t)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
z.scan(strings.NewReader(s), base, false)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) }
|
||||
func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) }
|
||||
func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) }
|
||||
func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) }
|
||||
func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
|
||||
|
||||
func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) }
|
||||
func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) }
|
||||
func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) }
|
||||
func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) }
|
||||
func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
|
||||
|
||||
func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) }
|
||||
func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) }
|
||||
func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) }
|
||||
func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) }
|
||||
func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
|
||||
|
||||
func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) }
|
||||
func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) }
|
||||
func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) }
|
||||
func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) }
|
||||
func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
|
||||
|
||||
func StringHelper(b *testing.B, base int, x, y Word) {
|
||||
b.StopTimer()
|
||||
var z nat
|
||||
z = z.expWW(x, y)
|
||||
z.string(lowercaseDigits[:base]) // warm divisor cache
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = z.string(lowercaseDigits[:base])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting
|
||||
func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) }
|
||||
func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) }
|
||||
func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) }
|
||||
func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) }
|
||||
func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) }
|
||||
func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) }
|
||||
func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) }
|
||||
func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) }
|
||||
func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) }
|
||||
func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
|
||||
func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
|
||||
func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
|
||||
func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
|
||||
func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
|
||||
func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
|
||||
func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
|
||||
func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
|
||||
func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
|
||||
|
||||
func LeafSizeHelper(b *testing.B, base Word, size int) {
|
||||
b.StopTimer()
|
||||
originalLeafSize := leafSize
|
||||
resetTable(cacheBase10.table[:])
|
||||
leafSize = size
|
||||
b.StartTimer()
|
||||
|
||||
for d := 1; d <= 10000; d *= 10 {
|
||||
b.StopTimer()
|
||||
var z nat
|
||||
z = z.expWW(base, Word(d)) // build target number
|
||||
_ = z.string(lowercaseDigits[:base]) // warm divisor cache
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = z.string(lowercaseDigits[:base])
|
||||
}
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
resetTable(cacheBase10.table[:])
|
||||
leafSize = originalLeafSize
|
||||
b.StartTimer()
|
||||
}
|
||||
|
||||
func resetTable(table []divisor) {
|
||||
if table != nil && table[0].bbb != nil {
|
||||
for i := 0; i < len(table); i++ {
|
||||
table[i].bbb = nil
|
||||
table[i].nbits = 0
|
||||
table[i].ndigits = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringPowers(t *testing.T) {
|
||||
var b, p Word
|
||||
for b = 2; b <= 16; b++ {
|
||||
for p = 0; p <= 512; p++ {
|
||||
x := nat(nil).expWW(b, p)
|
||||
xs := x.string(lowercaseDigits[:b])
|
||||
xs2 := toString(x, lowercaseDigits[:b])
|
||||
if xs != xs2 {
|
||||
t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
|
||||
}
|
||||
}
|
||||
if b >= 3 && testing.Short() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,570 @@
|
|||
// 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.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// A Rat represents a quotient a/b of arbitrary precision.
|
||||
// The zero value for a Rat represents the value 0.
|
||||
type Rat struct {
|
||||
// To make zero values for Rat work w/o initialization,
|
||||
// a zero value of b (len(b) == 0) acts like b == 1.
|
||||
// a.neg determines the sign of the Rat, b.neg is ignored.
|
||||
a, b Int
|
||||
}
|
||||
|
||||
// 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 {
|
||||
const expMask = 1<<11 - 1
|
||||
bits := math.Float64bits(f)
|
||||
mantissa := bits & (1<<52 - 1)
|
||||
exp := int((bits >> 52) & expMask)
|
||||
switch exp {
|
||||
case expMask: // non-finite
|
||||
return nil
|
||||
case 0: // denormal
|
||||
exp -= 1022
|
||||
default: // normal
|
||||
mantissa |= 1 << 52
|
||||
exp -= 1023
|
||||
}
|
||||
|
||||
shift := 52 - exp
|
||||
|
||||
// Optimization (?): partially pre-normalise.
|
||||
for mantissa&1 == 0 && shift > 0 {
|
||||
mantissa >>= 1
|
||||
shift--
|
||||
}
|
||||
|
||||
z.a.SetUint64(mantissa)
|
||||
z.a.neg = f < 0
|
||||
z.b.Set(intOne)
|
||||
if shift > 0 {
|
||||
z.b.Lsh(&z.b, uint(shift))
|
||||
} else {
|
||||
z.a.Lsh(&z.a, uint(-shift))
|
||||
}
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// quotToFloat32 returns the non-negative float32 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 quotToFloat32(a, b nat) (f float32, exact bool) {
|
||||
const (
|
||||
// float size in bits
|
||||
Fsize = 32
|
||||
|
||||
// mantissa
|
||||
Msize = 23
|
||||
Msize1 = Msize + 1 // incl. implicit 1
|
||||
Msize2 = Msize1 + 1
|
||||
|
||||
// exponent
|
||||
Esize = Fsize - Msize1
|
||||
Ebias = 1<<(Esize-1) - 1
|
||||
Emin = 1 - Ebias
|
||||
Emax = Ebias
|
||||
)
|
||||
|
||||
// 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<<Msize1, 1<<(Msize2+1)
|
||||
// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
|
||||
// This is 2 or 3 more than the float32 mantissa field width of Msize:
|
||||
// - the optional extra bit is shifted away in step 3 below.
|
||||
// - the high-order 1 is omitted in "normal" representation;
|
||||
// - the low-order 1 will be used during rounding then discarded.
|
||||
exp := alen - blen
|
||||
var a2, b2 nat
|
||||
a2 = a2.set(a)
|
||||
b2 = b2.set(b)
|
||||
if shift := Msize2 - exp; shift > 0 {
|
||||
a2 = a2.shl(a2, uint(shift))
|
||||
} else if shift < 0 {
|
||||
b2 = b2.shl(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.
|
||||
var q nat
|
||||
q, r := q.div(a2, a2, b2) // (recycle a2)
|
||||
mantissa := low32(q)
|
||||
haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
|
||||
|
||||
// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
|
||||
// (in effect---we accomplish this incrementally).
|
||||
if mantissa>>Msize2 == 1 {
|
||||
if mantissa&1 == 1 {
|
||||
haveRem = true
|
||||
}
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
if mantissa>>Msize1 != 1 {
|
||||
panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
|
||||
}
|
||||
|
||||
// 4. Rounding.
|
||||
if Emin-Msize <= exp && exp <= Emin {
|
||||
// Denormal case; lose 'shift' bits of precision.
|
||||
shift := uint(Emin - (exp - 1)) // [1..Esize1)
|
||||
lostbits := mantissa & (1<<shift - 1)
|
||||
haveRem = haveRem || lostbits != 0
|
||||
mantissa >>= shift
|
||||
exp = 2 - Ebias // == exp + shift
|
||||
}
|
||||
// Round q using round-half-to-even.
|
||||
exact = !haveRem
|
||||
if mantissa&1 != 0 {
|
||||
exact = false
|
||||
if haveRem || mantissa&2 != 0 {
|
||||
if mantissa++; mantissa >= 1<<Msize2 {
|
||||
// Complete rollover 11...1 => 100...0, so shift is safe
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
|
||||
|
||||
f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
|
||||
if math.IsInf(float64(f), 0) {
|
||||
exact = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// quotToFloat64 returns the non-negative float64 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 quotToFloat64(a, b nat) (f float64, exact bool) {
|
||||
const (
|
||||
// float size in bits
|
||||
Fsize = 64
|
||||
|
||||
// mantissa
|
||||
Msize = 52
|
||||
Msize1 = Msize + 1 // incl. implicit 1
|
||||
Msize2 = Msize1 + 1
|
||||
|
||||
// exponent
|
||||
Esize = Fsize - Msize1
|
||||
Ebias = 1<<(Esize-1) - 1
|
||||
Emin = 1 - Ebias
|
||||
Emax = Ebias
|
||||
)
|
||||
|
||||
// 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<<Msize1, 1<<(Msize2+1)
|
||||
// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
|
||||
// This is 2 or 3 more than the float64 mantissa field width of Msize:
|
||||
// - the optional extra bit is shifted away in step 3 below.
|
||||
// - the high-order 1 is omitted in "normal" representation;
|
||||
// - the low-order 1 will be used during rounding then discarded.
|
||||
exp := alen - blen
|
||||
var a2, b2 nat
|
||||
a2 = a2.set(a)
|
||||
b2 = b2.set(b)
|
||||
if shift := Msize2 - exp; shift > 0 {
|
||||
a2 = a2.shl(a2, uint(shift))
|
||||
} else if shift < 0 {
|
||||
b2 = b2.shl(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.
|
||||
var q nat
|
||||
q, r := q.div(a2, a2, b2) // (recycle a2)
|
||||
mantissa := low64(q)
|
||||
haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
|
||||
|
||||
// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
|
||||
// (in effect---we accomplish this incrementally).
|
||||
if mantissa>>Msize2 == 1 {
|
||||
if mantissa&1 == 1 {
|
||||
haveRem = true
|
||||
}
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
if mantissa>>Msize1 != 1 {
|
||||
panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
|
||||
}
|
||||
|
||||
// 4. Rounding.
|
||||
if Emin-Msize <= exp && exp <= Emin {
|
||||
// Denormal case; lose 'shift' bits of precision.
|
||||
shift := uint(Emin - (exp - 1)) // [1..Esize1)
|
||||
lostbits := mantissa & (1<<shift - 1)
|
||||
haveRem = haveRem || lostbits != 0
|
||||
mantissa >>= shift
|
||||
exp = 2 - Ebias // == exp + shift
|
||||
}
|
||||
// Round q using round-half-to-even.
|
||||
exact = !haveRem
|
||||
if mantissa&1 != 0 {
|
||||
exact = false
|
||||
if haveRem || mantissa&2 != 0 {
|
||||
if mantissa++; mantissa >= 1<<Msize2 {
|
||||
// Complete rollover 11...1 => 100...0, so shift is safe
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
|
||||
|
||||
f = math.Ldexp(float64(mantissa), exp-Msize1)
|
||||
if math.IsInf(f, 0) {
|
||||
exact = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float32 returns the nearest float32 value for x and a bool indicating
|
||||
// whether f represents x exactly. If the magnitude of x is too large to
|
||||
// be represented by a float32, f is an infinity and exact is false.
|
||||
// The sign of f always matches the sign of x, even if f == 0.
|
||||
func (x *Rat) Float32() (f float32, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
}
|
||||
f, exact = quotToFloat32(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
f = -f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float64 returns the nearest float64 value for x and a bool indicating
|
||||
// whether f represents x exactly. If the magnitude of x 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 x, even if f == 0.
|
||||
func (x *Rat) Float64() (f float64, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
}
|
||||
f, exact = quotToFloat64(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
f = -f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetFrac sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac(a, b *Int) *Rat {
|
||||
z.a.neg = a.neg != b.neg
|
||||
babs := b.abs
|
||||
if len(babs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
if &z.a == b || alias(z.a.abs, babs) {
|
||||
babs = nat(nil).set(babs) // make a copy
|
||||
}
|
||||
z.a.abs = z.a.abs.set(a.abs)
|
||||
z.b.abs = z.b.abs.set(babs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// SetFrac64 sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac64(a, b int64) *Rat {
|
||||
z.a.SetInt64(a)
|
||||
if b == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
if b < 0 {
|
||||
b = -b
|
||||
z.a.neg = !z.a.neg
|
||||
}
|
||||
z.b.abs = z.b.abs.setUint64(uint64(b))
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// SetInt sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) SetInt(x *Int) *Rat {
|
||||
z.a.Set(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Rat) SetInt64(x int64) *Rat {
|
||||
z.a.SetInt64(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
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.a.Set(&x.a)
|
||||
z.b.Set(&x.b)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func (z *Rat) Abs(x *Rat) *Rat {
|
||||
z.Set(x)
|
||||
z.a.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func (z *Rat) Neg(x *Rat) *Rat {
|
||||
z.Set(x)
|
||||
z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
|
||||
return z
|
||||
}
|
||||
|
||||
// Inv sets z to 1/x and returns z.
|
||||
func (z *Rat) Inv(x *Rat) *Rat {
|
||||
if len(x.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
z.Set(x)
|
||||
a := z.b.abs
|
||||
if len(a) == 0 {
|
||||
a = a.set(natOne) // materialize numerator
|
||||
}
|
||||
b := z.a.abs
|
||||
if b.cmp(natOne) == 0 {
|
||||
b = b[:0] // normalize denominator
|
||||
}
|
||||
z.a.abs, z.b.abs = a, b // sign doesn't change
|
||||
return z
|
||||
}
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if x < 0
|
||||
// 0 if x == 0
|
||||
// +1 if x > 0
|
||||
//
|
||||
func (x *Rat) Sign() int {
|
||||
return x.a.Sign()
|
||||
}
|
||||
|
||||
// IsInt reports whether the denominator of x is 1.
|
||||
func (x *Rat) IsInt() bool {
|
||||
return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
|
||||
}
|
||||
|
||||
// Num returns the numerator of x; it may be <= 0.
|
||||
// The result is a reference to x's numerator; it
|
||||
// may change if a new value is assigned to x, and vice versa.
|
||||
// The sign of the numerator corresponds to the sign of x.
|
||||
func (x *Rat) Num() *Int {
|
||||
return &x.a
|
||||
}
|
||||
|
||||
// Denom returns the denominator of x; it is always > 0.
|
||||
// The result is a reference to x's denominator; it
|
||||
// may change if a new value is assigned to x, and vice versa.
|
||||
func (x *Rat) Denom() *Int {
|
||||
x.b.neg = false // the result is always >= 0
|
||||
if len(x.b.abs) == 0 {
|
||||
x.b.abs = x.b.abs.set(natOne) // materialize denominator
|
||||
}
|
||||
return &x.b
|
||||
}
|
||||
|
||||
func (z *Rat) norm() *Rat {
|
||||
switch {
|
||||
case len(z.a.abs) == 0:
|
||||
// z == 0 - normalize sign and denominator
|
||||
z.a.neg = false
|
||||
z.b.abs = z.b.abs[:0]
|
||||
case len(z.b.abs) == 0:
|
||||
// z is normalized int - nothing to do
|
||||
case z.b.abs.cmp(natOne) == 0:
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
default:
|
||||
neg := z.a.neg
|
||||
z.a.neg = false
|
||||
z.b.neg = false
|
||||
if f := NewInt(0).binaryGCD(&z.a, &z.b); f.Cmp(intOne) != 0 {
|
||||
z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
|
||||
z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
|
||||
if z.b.abs.cmp(natOne) == 0 {
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
}
|
||||
}
|
||||
z.a.neg = neg
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// mulDenom sets z to the denominator product x*y (by taking into
|
||||
// account that 0 values for x or y must be interpreted as 1) and
|
||||
// returns z.
|
||||
func mulDenom(z, x, y nat) nat {
|
||||
switch {
|
||||
case len(x) == 0:
|
||||
return z.set(y)
|
||||
case len(y) == 0:
|
||||
return z.set(x)
|
||||
}
|
||||
return z.mul(x, y)
|
||||
}
|
||||
|
||||
// scaleDenom computes x*f.
|
||||
// If f == 0 (zero value of denominator), the result is (a copy of) x.
|
||||
func scaleDenom(x *Int, f nat) *Int {
|
||||
var z Int
|
||||
if len(f) == 0 {
|
||||
return z.Set(x)
|
||||
}
|
||||
z.abs = z.abs.mul(x.abs, f)
|
||||
z.neg = x.neg
|
||||
return &z
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
//
|
||||
func (x *Rat) Cmp(y *Rat) int {
|
||||
return scaleDenom(&x.a, y.b.abs).Cmp(scaleDenom(&y.a, x.b.abs))
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func (z *Rat) Add(x, y *Rat) *Rat {
|
||||
a1 := scaleDenom(&x.a, y.b.abs)
|
||||
a2 := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.Add(a1, a2)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Sub sets z to the difference x-y and returns z.
|
||||
func (z *Rat) Sub(x, y *Rat) *Rat {
|
||||
a1 := scaleDenom(&x.a, y.b.abs)
|
||||
a2 := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.Sub(a1, a2)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Mul sets z to the product x*y and returns z.
|
||||
func (z *Rat) Mul(x, y *Rat) *Rat {
|
||||
z.a.Mul(&x.a, &y.a)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if len(y.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
a := scaleDenom(&x.a, y.b.abs)
|
||||
b := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.abs = a.abs
|
||||
z.b.abs = b.abs
|
||||
z.a.neg = a.neg != b.neg
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const ratGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (x *Rat) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
|
||||
i := x.b.abs.bytes(buf)
|
||||
j := x.a.abs.bytes(buf[:i])
|
||||
n := i - j
|
||||
if int(uint32(n)) != n {
|
||||
// this should never happen
|
||||
return nil, errors.New("Rat.GobEncode: numerator too large")
|
||||
}
|
||||
binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
|
||||
j -= 1 + 4
|
||||
b := ratGobVersion << 1 // make space for sign bit
|
||||
if x.a.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[j] = b
|
||||
return buf[j:], nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Rat) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Rat{}
|
||||
return nil
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != ratGobVersion {
|
||||
return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
|
||||
}
|
||||
const j = 1 + 4
|
||||
i := j + binary.BigEndian.Uint32(buf[j-4:j])
|
||||
z.a.neg = b&1 != 0
|
||||
z.a.abs = z.a.abs.setBytes(buf[j:i])
|
||||
z.b.abs = z.b.abs.setBytes(buf[i:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (r *Rat) MarshalText() (text []byte, err error) {
|
||||
return []byte(r.RatString()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (r *Rat) UnmarshalText(text []byte) error {
|
||||
if _, ok := r.SetString(string(text)); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,736 @@
|
|||
// 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.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"math"
|
||||
"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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
|
||||
// TODO: top-level nils.
|
||||
func TestGobEncodingNilRatInSlice(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
dec := gob.NewDecoder(buf)
|
||||
|
||||
var in = make([]*Rat, 1)
|
||||
err := enc.Encode(&in)
|
||||
if err != nil {
|
||||
t.Errorf("gob encode failed: %q", err)
|
||||
}
|
||||
var out []*Rat
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
t.Fatalf("gob decode failed: %q", err)
|
||||
}
|
||||
if len(out) != 1 {
|
||||
t.Fatalf("wrong len; want 1 got %d", len(out))
|
||||
}
|
||||
var zero Rat
|
||||
if out[0].Cmp(&zero) != 0 {
|
||||
t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
|
||||
}
|
||||
}
|
||||
|
||||
var ratNums = []string{
|
||||
"-141592653589793238462643383279502884197169399375105820974944592307816406286",
|
||||
"-1415926535897932384626433832795028841971",
|
||||
"-141592653589793",
|
||||
"-1",
|
||||
"0",
|
||||
"1",
|
||||
"141592653589793",
|
||||
"1415926535897932384626433832795028841971",
|
||||
"141592653589793238462643383279502884197169399375105820974944592307816406286",
|
||||
}
|
||||
|
||||
var ratDenoms = []string{
|
||||
"1",
|
||||
"718281828459045",
|
||||
"7182818284590452353602874713526624977572",
|
||||
"718281828459045235360287471352662497757247093699959574966967627724076630353",
|
||||
}
|
||||
|
||||
func TestRatJSONEncoding(t *testing.T) {
|
||||
for _, num := range ratNums {
|
||||
for _, denom := range ratDenoms {
|
||||
var tx Rat
|
||||
tx.SetString(num + "/" + denom)
|
||||
b, err := json.Marshal(&tx)
|
||||
if err != nil {
|
||||
t.Errorf("marshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
var rx Rat
|
||||
if err := json.Unmarshal(b, &rx); err != nil {
|
||||
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRatXMLEncoding(t *testing.T) {
|
||||
for _, num := range ratNums {
|
||||
for _, denom := range ratDenoms {
|
||||
var tx Rat
|
||||
tx.SetString(num + "/" + denom)
|
||||
b, err := xml.Marshal(&tx)
|
||||
if err != nil {
|
||||
t.Errorf("marshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
var rx Rat
|
||||
if err := xml.Unmarshal(b, &rx); err != nil {
|
||||
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("XML encoding 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.Denom().Set(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.Num().Set(a)
|
||||
qab := new(Rat).SetFrac(a, b)
|
||||
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.Denom().SetInt64(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.Denom().SetInt64(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)
|
||||
a = x.Num()
|
||||
b = x.Denom()
|
||||
a.SetInt64(5)
|
||||
b.SetInt64(3)
|
||||
if x.Cmp(q53) != 0 {
|
||||
t.Errorf("3) got %s want %s", x, q53)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat32Distribution(t *testing.T) {
|
||||
// Generate a distribution of (sign, mantissa, exp) values
|
||||
// broader than the float32 range, and check Rat.Float32()
|
||||
// always picks the closest float32 approximation.
|
||||
var add = []int64{
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
9,
|
||||
11,
|
||||
}
|
||||
var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
|
||||
if testing.Short() {
|
||||
winc, einc = 5, 15 // quick test (~60ms on x86-64)
|
||||
}
|
||||
|
||||
for _, sign := range "+-" {
|
||||
for _, a := range add {
|
||||
for wid := uint64(0); wid < 30; wid += winc {
|
||||
b := 1<<wid + a
|
||||
if sign == '-' {
|
||||
b = -b
|
||||
}
|
||||
for exp := -150; exp < 150; 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.Float32()
|
||||
|
||||
if !checkIsBestApprox32(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)
|
||||
}
|
||||
|
||||
checkNonLossyRoundtrip32(t, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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), 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 := 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 !checkIsBestApprox64(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)
|
||||
}
|
||||
|
||||
checkNonLossyRoundtrip64(t, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSetFloat64NonFinite 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkNonLossyRoundtrip32 checks that a float->Rat->float roundtrip is
|
||||
// non-lossy for finite f.
|
||||
func checkNonLossyRoundtrip32(t *testing.T, f float32) {
|
||||
if !isFinite(float64(f)) {
|
||||
return
|
||||
}
|
||||
r := new(Rat).SetFloat64(float64(f))
|
||||
if r == nil {
|
||||
t.Errorf("Rat.SetFloat64(float64(%g) (%b)) == nil", f, f)
|
||||
return
|
||||
}
|
||||
f2, exact := r.Float32()
|
||||
if f != f2 || !exact {
|
||||
t.Errorf("Rat.SetFloat64(float64(%g)).Float32() = %g (%b), %v, want %g (%b), %v; delta = %b",
|
||||
f, f2, f2, exact, f, f, true, f2-f)
|
||||
}
|
||||
}
|
||||
|
||||
// checkNonLossyRoundtrip64 checks that a float->Rat->float roundtrip is
|
||||
// non-lossy for finite f.
|
||||
func checkNonLossyRoundtrip64(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)
|
||||
}
|
||||
|
||||
// checkIsBestApprox32 checks that f is the best possible float32
|
||||
// approximation of r.
|
||||
// Returns true on success.
|
||||
func checkIsBestApprox32(t *testing.T, f float32, r *Rat) bool {
|
||||
if math.Abs(float64(f)) >= math.MaxFloat32 {
|
||||
// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat32).
|
||||
// But we have tests for these special cases.
|
||||
return true
|
||||
}
|
||||
|
||||
// r must be strictly between f0 and f1, the floats bracketing f.
|
||||
f0 := math.Nextafter32(f, float32(math.Inf(-1)))
|
||||
f1 := math.Nextafter32(f, float32(math.Inf(+1)))
|
||||
|
||||
// For f to be correct, r must be closer to f than to f0 or f1.
|
||||
df := delta(r, float64(f))
|
||||
df0 := delta(r, float64(f0))
|
||||
df1 := delta(r, float64(f1))
|
||||
if df.Cmp(df0) > 0 {
|
||||
t.Errorf("Rat(%v).Float32() = %g (%b), but previous float32 %g (%b) is closer", r, f, f, f0, f0)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df1) > 0 {
|
||||
t.Errorf("Rat(%v).Float32() = %g (%b), but next float32 %g (%b) is closer", r, f, f, f1, f1)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df0) == 0 && !isEven32(f) {
|
||||
t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
|
||||
return false
|
||||
}
|
||||
if df.Cmp(df1) == 0 && !isEven32(f) {
|
||||
t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// checkIsBestApprox64 checks that f is the best possible float64
|
||||
// approximation of r.
|
||||
// Returns true on success.
|
||||
func checkIsBestApprox64(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 && !isEven64(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 && !isEven64(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 isEven32(f float32) bool { return math.Float32bits(f)&1 == 0 }
|
||||
func isEven64(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
// Copyright 2015 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 rat-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
// len(s) > 0
|
||||
|
||||
// parse fraction a/b, if any
|
||||
if sep := strings.Index(s, "/"); sep >= 0 {
|
||||
if _, ok := z.a.SetString(s[:sep], 0); !ok {
|
||||
return nil, false
|
||||
}
|
||||
s = s[sep+1:]
|
||||
var err error
|
||||
if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
if len(z.b.abs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return z.norm(), true
|
||||
}
|
||||
|
||||
// parse floating-point number
|
||||
r := strings.NewReader(s)
|
||||
|
||||
// sign
|
||||
neg, err := scanSign(r)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// mantissa
|
||||
var ecorr int
|
||||
z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// exponent
|
||||
var exp int64
|
||||
exp, _, err = scanExponent(r, false)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// there should be no unread characters left
|
||||
if _, err = r.ReadByte(); err != io.EOF {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// correct exponent
|
||||
if ecorr < 0 {
|
||||
exp += int64(ecorr)
|
||||
}
|
||||
|
||||
// compute exponent power
|
||||
expabs := exp
|
||||
if expabs < 0 {
|
||||
expabs = -expabs
|
||||
}
|
||||
powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
|
||||
|
||||
// complete fraction
|
||||
if exp < 0 {
|
||||
z.b.abs = powTen
|
||||
z.norm()
|
||||
} else {
|
||||
z.a.abs = z.a.abs.mul(z.a.abs, powTen)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
}
|
||||
|
||||
z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
|
||||
|
||||
return z, true
|
||||
}
|
||||
|
||||
// scanExponent scans the longest possible prefix of r representing a decimal
|
||||
// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
|
||||
// exponent base (10 or 2), or a read or syntax error, if any.
|
||||
//
|
||||
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
|
||||
// sign = "+" | "-" .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" .
|
||||
//
|
||||
// A binary exponent is only permitted if binExpOk is set.
|
||||
func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
|
||||
base = 10
|
||||
|
||||
var ch byte
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil // no exponent; same as e0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch ch {
|
||||
case 'e', 'E':
|
||||
// ok
|
||||
case 'p':
|
||||
if binExpOk {
|
||||
base = 2
|
||||
break // ok
|
||||
}
|
||||
fallthrough // binary exponent not permitted
|
||||
default:
|
||||
r.UnreadByte()
|
||||
return // no exponent; same as e0
|
||||
}
|
||||
|
||||
var neg bool
|
||||
if neg, err = scanSign(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var digits []byte
|
||||
if neg {
|
||||
digits = append(digits, '-')
|
||||
}
|
||||
|
||||
// no need to use nat.scan for exponent digits
|
||||
// since we only care about int64 values - the
|
||||
// from-scratch scan is easy enough and faster
|
||||
for i := 0; ; i++ {
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err != io.EOF || i == 0 {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
break // i > 0
|
||||
}
|
||||
if ch < '0' || '9' < ch {
|
||||
if i == 0 {
|
||||
r.UnreadByte()
|
||||
err = fmt.Errorf("invalid exponent (missing digits)")
|
||||
return
|
||||
}
|
||||
break // i > 0
|
||||
}
|
||||
digits = append(digits, byte(ch))
|
||||
}
|
||||
// i > 0 => we have at least one digit
|
||||
|
||||
exp, err = strconv.ParseInt(string(digits), 10, 64)
|
||||
return
|
||||
}
|
||||
|
||||
// String returns a string representation of x in the form "a/b" (even if b == 1).
|
||||
func (x *Rat) String() string {
|
||||
s := "/1"
|
||||
if len(x.b.abs) != 0 {
|
||||
s = "/" + x.b.abs.decimalString()
|
||||
}
|
||||
return x.a.String() + s
|
||||
}
|
||||
|
||||
// RatString returns a string representation of x in the form "a/b" if b != 1,
|
||||
// and in the form "a" if b == 1.
|
||||
func (x *Rat) RatString() string {
|
||||
if x.IsInt() {
|
||||
return x.a.String()
|
||||
}
|
||||
return x.String()
|
||||
}
|
||||
|
||||
// FloatString returns a string representation of x in decimal form with prec
|
||||
// digits of precision after the decimal point and the last digit rounded.
|
||||
func (x *Rat) FloatString(prec int) string {
|
||||
if x.IsInt() {
|
||||
s := x.a.String()
|
||||
if prec > 0 {
|
||||
s += "." + strings.Repeat("0", prec)
|
||||
}
|
||||
return s
|
||||
}
|
||||
// x.b.abs != 0
|
||||
|
||||
q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
|
||||
|
||||
p := natOne
|
||||
if prec > 0 {
|
||||
p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
|
||||
}
|
||||
|
||||
r = r.mul(r, p)
|
||||
r, r2 := r.div(nat(nil), r, x.b.abs)
|
||||
|
||||
// see if we need to round up
|
||||
r2 = r2.add(r2, r2)
|
||||
if x.b.abs.cmp(r2) <= 0 {
|
||||
r = r.add(r, natOne)
|
||||
if r.cmp(p) >= 0 {
|
||||
q = nat(nil).add(q, natOne)
|
||||
r = nat(nil).sub(r, p)
|
||||
}
|
||||
}
|
||||
|
||||
s := q.decimalString()
|
||||
if x.a.neg {
|
||||
s = "-" + s
|
||||
}
|
||||
|
||||
if prec > 0 {
|
||||
rs := r.decimalString()
|
||||
leadingZeros := prec - len(rs)
|
||||
s += "." + strings.Repeat("0", leadingZeros) + rs
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
@ -0,0 +1,451 @@
|
|||
// Copyright 2015 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 big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type StringTest struct {
|
||||
in, out string
|
||||
ok bool
|
||||
}
|
||||
|
||||
var setStringTests = []StringTest{
|
||||
{"0", "0", true},
|
||||
{"-0", "0", true},
|
||||
{"1", "1", true},
|
||||
{"-1", "-1", true},
|
||||
{"1.", "1", true},
|
||||
{"1e0", "1", true},
|
||||
{"1.e1", "10", true},
|
||||
{in: "1e"},
|
||||
{in: "1.e"},
|
||||
{in: "1e+14e-5"},
|
||||
{in: "1e4.5"},
|
||||
{in: "r"},
|
||||
{in: "a/b"},
|
||||
{in: "a.b"},
|
||||
{"-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},
|
||||
{in: "1/0"},
|
||||
}
|
||||
|
||||
// These are not supported by fmt.Fscanf.
|
||||
var setStringTests2 = []StringTest{
|
||||
{"0x10", "16", true},
|
||||
{"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
|
||||
{"-010.", "-10", true},
|
||||
{"0x10/0x20", "1/2", true},
|
||||
{"0b1000/3", "8/3", true},
|
||||
// TODO(gri) add more tests
|
||||
}
|
||||
|
||||
func TestRatSetString(t *testing.T) {
|
||||
var tests []StringTest
|
||||
tests = append(tests, setStringTests...)
|
||||
tests = append(tests, setStringTests2...)
|
||||
|
||||
for i, test := range tests {
|
||||
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 (%s) error: %s", i, test.in, err)
|
||||
} else {
|
||||
t.Errorf("#%d (%s) expected error", i, test.in)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 TestFloat32SpecialCases(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.Float32()
|
||||
|
||||
// 1. Check string -> Rat -> float32 conversions are
|
||||
// consistent with strconv.ParseFloat.
|
||||
// Skip this check if the input uses "a/b" rational syntax.
|
||||
if !strings.Contains(input, "/") {
|
||||
e64, _ := strconv.ParseFloat(input, 32)
|
||||
e := float32(e64)
|
||||
|
||||
// Careful: negative Rats too small for
|
||||
// float64 become -0, but Rat obviously cannot
|
||||
// preserve the sign from SetString("-0").
|
||||
switch {
|
||||
case math.Float32bits(e) == math.Float32bits(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(float64(f)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 2. Check f is best approximation to r.
|
||||
if !checkIsBestApprox32(t, f, r) {
|
||||
// Append context information.
|
||||
t.Errorf("(input was %q)", input)
|
||||
}
|
||||
|
||||
// 3. Check f->R->f roundtrip is non-lossy.
|
||||
checkNonLossyRoundtrip32(t, f)
|
||||
|
||||
// 4. Check exactness using slow algorithm.
|
||||
if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
|
||||
t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 !checkIsBestApprox64(t, f, r) {
|
||||
// Append context information.
|
||||
t.Errorf("(input was %q)", input)
|
||||
}
|
||||
|
||||
// 3. Check f->R->f roundtrip is non-lossy.
|
||||
checkNonLossyRoundtrip64(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// generated by stringer -type=RoundingMode; DO NOT EDIT
|
||||
|
||||
package big
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf"
|
||||
|
||||
var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70}
|
||||
|
||||
func (i RoundingMode) String() string {
|
||||
if i+1 >= RoundingMode(len(_RoundingMode_index)) {
|
||||
return fmt.Sprintf("RoundingMode(%d)", i)
|
||||
}
|
||||
return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2015 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.
|
||||
|
||||
# Run this script to obtain an up-to-date vendored version of math/big.
|
||||
|
||||
BIGDIR=../../../../math/big
|
||||
|
||||
# Start from scratch.
|
||||
rm *.go
|
||||
|
||||
# We don't want any assembly files.
|
||||
cp $BIGDIR/*.go .
|
||||
|
||||
# Use pure Go arith ops w/o build tag.
|
||||
sed 's/^\/\/ \+build math_big_pure_go$//' arith_decl_pure.go > arith_decl.go
|
||||
rm arith_decl_pure.go
|
||||
|
||||
# Test that it works
|
||||
go test -short
|
||||
Loading…
Reference in New Issue