大整数库实现 #3
|
|
@ -1,4 +1,3 @@
|
|||
bigint_go
|
||||
src
|
||||
|
||||
*.wasm
|
||||
*.wat
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
var (
|
||||
天干 = []string{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"}
|
||||
地支 = []string{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}
|
||||
)
|
||||
var base60Table = [64]string{}
|
||||
|
||||
// var base60IndexTable = map[string]int{}
|
||||
|
||||
func init() {
|
||||
for i := 0; i < 64; i++ {
|
||||
base60Table[i] = 天干[i%10] + 地支[i%12]
|
||||
// base60IndexTable[base60Table[i]] = i
|
||||
}
|
||||
}
|
||||
|
||||
func base60Encode(buf: []byte) => string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func base60Decode(s: string) => []byte {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import "base60/big"
|
||||
|
||||
func Test_base60() {
|
||||
println("Hello")
|
||||
big.AAA()
|
||||
|
||||
// Output:
|
||||
// Hello
|
||||
// 32
|
||||
}
|
||||
|
||||
func Test_Norm() {
|
||||
big.Test_Norm()
|
||||
|
||||
// Output:
|
||||
// NORM TEST PASS!
|
||||
}
|
||||
|
||||
func Test_setWord {
|
||||
big.Test_setWord()
|
||||
|
||||
// Output:
|
||||
// set zero: 0
|
||||
// set to 10: 10 10
|
||||
}
|
||||
|
||||
func Test_set {
|
||||
big.Test_set()
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// item: 1 === 1
|
||||
// item: 2 === 2
|
||||
// item: 3 === 3
|
||||
// item: 4 === 4
|
||||
}
|
||||
|
||||
func Test_add_sub {
|
||||
big.Test_add()
|
||||
|
||||
// Output:
|
||||
// start test add
|
||||
}
|
||||
|
||||
func Test_sub {
|
||||
big.Test_sub()
|
||||
|
||||
// Output:
|
||||
// start test sub
|
||||
}
|
||||
|
||||
func Test_mul {
|
||||
big.Test_mul()
|
||||
|
||||
// Output:
|
||||
// start test mul
|
||||
}
|
||||
|
||||
func Test_setString {
|
||||
big.Test_setString()
|
||||
|
||||
// Output:
|
||||
// 1796636465
|
||||
// 5326
|
||||
}
|
||||
|
||||
func Test_div {
|
||||
big.Test_div()
|
||||
|
||||
// Output:
|
||||
// ok div result
|
||||
// ok div remainder result
|
||||
}
|
||||
|
||||
func Test_int_set {
|
||||
big.Test_Int_Set()
|
||||
|
||||
// Output:
|
||||
// start test set
|
||||
}
|
||||
|
||||
func Test_Int_Sum {
|
||||
big.Test_Int_Sum()
|
||||
// Output:
|
||||
// start test int add and sub
|
||||
}
|
||||
|
||||
func Test_Int_Quo {
|
||||
big.Test_Quo()
|
||||
// Output:
|
||||
// start test int quo
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
type funZZ func(z, x, y: *Int) => *Int
|
||||
type argZZ struct {
|
||||
z, x, y: *Int
|
||||
}
|
||||
|
||||
var sumZZ = []argZZ{
|
||||
{NewInt("0"), NewInt("0"), NewInt("0")},
|
||||
{NewInt("1"), NewInt("1"), NewInt("0")},
|
||||
{NewInt("1111111110"), NewInt("123456789"), NewInt("987654321")},
|
||||
{NewInt("-1"), NewInt("-1"), NewInt("0")},
|
||||
{NewInt("864197532"), NewInt("-123456789"), NewInt("987654321")},
|
||||
{NewInt("-1111111110"), NewInt("-123456789"), NewInt("-987654321")},
|
||||
}
|
||||
|
||||
func Test_Int_Set() {
|
||||
println("start test set")
|
||||
for _, a := range sumZZ {
|
||||
z: Int
|
||||
z.Set(a.z)
|
||||
if (&z).Cmp(a.z) != 0 {
|
||||
println("error for Int Set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFunZZ(msg: string, f: funZZ, a: argZZ) {
|
||||
z: Int
|
||||
f(&z, a.x, a.y)
|
||||
t := (&z).Cmp(a.z)
|
||||
if t != 0 {
|
||||
println(msg, " compute error ", t, ".")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Int_Sum() {
|
||||
println("start test int add and sub")
|
||||
AddZZ := func(z, x, y: *Int) => *Int { return z.Add(x, y) }
|
||||
SubZZ := func(z, x, y: *Int) => *Int { return z.Sub(x, y) }
|
||||
|
||||
for _, a := range sumZZ {
|
||||
arg := a
|
||||
testFunZZ("AddZZ", AddZZ, arg)
|
||||
|
||||
arg = argZZ{a.z, a.y, a.x}
|
||||
testFunZZ("AddZZ symmetric", AddZZ, arg)
|
||||
|
||||
arg = argZZ{a.x, a.z, a.y}
|
||||
testFunZZ("SubZZ", SubZZ, arg)
|
||||
|
||||
arg = argZZ{a.y, a.z, a.x}
|
||||
testFunZZ("SubZZ symmetric", SubZZ, arg)
|
||||
}
|
||||
}
|
||||
|
||||
var quoTests = []struct {
|
||||
x, y: string
|
||||
q, r: string
|
||||
}{
|
||||
{
|
||||
"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
|
||||
"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
|
||||
"50911",
|
||||
"1",
|
||||
},
|
||||
{
|
||||
"11510768301994997771168",
|
||||
"1328165573307167369775",
|
||||
"8",
|
||||
"885443715537658812968",
|
||||
},
|
||||
}
|
||||
|
||||
func Test_Quo() {
|
||||
println("start test int quo")
|
||||
|
||||
for _, test := range quoTests {
|
||||
x := NewInt(test.x)
|
||||
y := NewInt(test.y)
|
||||
expectedQ := NewInt(test.q)
|
||||
expectedR := NewInt(test.r)
|
||||
|
||||
r := NewInt("0")
|
||||
q, r := NewInt("0").QuoRem(x, y, r)
|
||||
|
||||
if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
|
||||
println("error for Int quo")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
// test好像并不执行该文件夹, 改为导出方法放在外层执行
|
||||
func Test_Norm {
|
||||
t := nat{Data: []uint{1, 0, 0, 0}}
|
||||
t = t.norm()
|
||||
if len(t.Data) == 1 && t.Data[0] == 1 {
|
||||
println("NORM TEST PASS!")
|
||||
} else {
|
||||
println("NORM TEST FAILED!")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_setWord {
|
||||
t := nat{Data: []uint{1, 2, 3, 4}}
|
||||
z := t.setWord(0)
|
||||
println("set zero:", len(z.Data))
|
||||
|
||||
z = t.setWord(10)
|
||||
println("set to 10:", z.Data[0], " ", t.Data[0])
|
||||
}
|
||||
|
||||
func Test_set {
|
||||
t := nat{Data: []uint{1, 2, 3, 4}}
|
||||
z := t.set(t)
|
||||
println(len(z.Data) == len(t.Data))
|
||||
for i := 0; i < len(z.Data); i++ {
|
||||
println("item:", z.Data[i], "===", t.Data[i])
|
||||
}
|
||||
}
|
||||
|
||||
// 参考go单元测试的内容
|
||||
type funNN func(z: nat, x: nat, y: nat) => nat
|
||||
type argNN struct {
|
||||
z: nat
|
||||
x: nat
|
||||
y: nat
|
||||
}
|
||||
|
||||
var sumNN = []argNN{
|
||||
{},
|
||||
{z: nat{[]uint{1}}, x: nat{nil}, y: nat{[]uint{1}}},
|
||||
{z: nat{[]uint{1111111110}}, x: nat{[]uint{123456789}}, y: nat{[]uint{987654321}}},
|
||||
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{nil}, y: nat{[]uint{0, 0, 0, 1}}},
|
||||
{z: nat{[]uint{0, 0, 0, 1111111110}}, x: nat{[]uint{0, 0, 0, 123456789}}, y: nat{Data: []uint{0, 0, 0, 987654321}}},
|
||||
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{[]uint{0, 0, _M}}, y: nat{[]uint{0, 0, 1}}},
|
||||
}
|
||||
|
||||
var prodNN = []argNN{
|
||||
{},
|
||||
{z: nat{nil}, x: nat{nil}, y: nat{nil}},
|
||||
{z: nat{nil}, x: nat{[]uint{991}}, y: nat{nil}},
|
||||
{z: nat{[]uint{991}}, x: nat{[]uint{991}}, y: nat{[]uint{1}}},
|
||||
{z: nat{[]uint{991 * 991}}, x: nat{[]uint{991}}, y: nat{[]uint{991}}},
|
||||
{z: nat{[]uint{0, 0, 991 * 991}}, x: nat{[]uint{0, 991}}, y: nat{[]uint{0, 991}}},
|
||||
{z: nat{[]uint{1 * 991, 2 * 991, 3 * 991, 4 * 991}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{991}}},
|
||||
{z: nat{[]uint{4, 11, 20, 30, 20, 11, 4}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{4, 3, 2, 1}}},
|
||||
{
|
||||
z: natFromString("11790184577738583171520872861412518665678211592275841109096961"),
|
||||
x: natFromString("515377520732011331036461129765621272702107522001"),
|
||||
y: natFromString("22876792454961"),
|
||||
},
|
||||
}
|
||||
|
||||
func testAdd(a: argNN) {
|
||||
temp := &nat{Data: nil}
|
||||
z := temp.add(a.x, a.y)
|
||||
if z.cmp(a.z) != 0 {
|
||||
println("Error for add result")
|
||||
}
|
||||
}
|
||||
|
||||
func testSub(a: argNN) {
|
||||
temp := &nat{Data: nil}
|
||||
z := temp.sub(a.x, a.y)
|
||||
if z.cmp(a.z) != 0 {
|
||||
println("Error for sub result")
|
||||
}
|
||||
}
|
||||
|
||||
func testMul(a: argNN) {
|
||||
temp := &nat{Data: nil}
|
||||
z := temp.mul(a.x, a.y)
|
||||
if z.cmp(a.z) != 0 {
|
||||
println("Error for mul result")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_add {
|
||||
println("start test add")
|
||||
for _, a := range sumNN {
|
||||
testAdd(a)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_sub {
|
||||
println("start test sub")
|
||||
for _, a := range sumNN {
|
||||
arg := argNN{a.x, a.z, a.y}
|
||||
testSub(arg)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mul {
|
||||
println("start test mul")
|
||||
for _, a := range prodNN {
|
||||
arg := a
|
||||
testMul(arg)
|
||||
|
||||
arg = argNN{a.z, a.y, a.x}
|
||||
testMul(arg)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_div {
|
||||
u := natFromString("11790184577738583171520872861412518665678211592275841109096961")
|
||||
v := natFromString("515377520732011331036461129765621272702107522001")
|
||||
w := natFromString("22876792454961") // 商
|
||||
r := natFromString("0") // 余数
|
||||
|
||||
q := &nat{nil}
|
||||
q2, r2 := q.div(nat{nil}, u, v)
|
||||
|
||||
if q2.cmp(w) != 0 {
|
||||
println("wrong div result")
|
||||
} else {
|
||||
println("ok div result")
|
||||
}
|
||||
if r2.cmp(r) != 0 {
|
||||
println("wrong div remainder result")
|
||||
} else {
|
||||
println("ok div remainder result")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_setString {
|
||||
n := natFromString("22876792454961")
|
||||
for _, i := range n.Data {
|
||||
println(i)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
import "math/bits"
|
||||
|
||||
func AAA {
|
||||
println(bits.UintSize)
|
||||
}
|
||||
|
||||
const (
|
||||
_S = _W / 8 // 字宽(以字节为单位)
|
||||
|
||||
_W = bits.UintSize // 字宽(以位为单位)
|
||||
_B = 1 << _W // 基数
|
||||
_M = _B - 1 // 基数掩码
|
||||
)
|
||||
|
||||
// z1<<_W + z0 = x*y
|
||||
func mulWW(x, y: uint) => (z1, z0: uint) {
|
||||
return bits.Mul(x, y)
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x*y + c
|
||||
func mulAddWWW(x, y, c: uint) => (z1, z0: uint) {
|
||||
hi, lo := bits.Mul(x, y)
|
||||
cc: uint
|
||||
lo, cc = bits.Add(lo, c, 0)
|
||||
return hi + cc, lo
|
||||
}
|
||||
|
||||
// nlz returns the number of leading zeros in x.
|
||||
// Wraps bits.LeadingZeros call for convenience.
|
||||
func nlz(x: uint) => uint {
|
||||
return uint(bits.LeadingZeros(x))
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVV(z, x, y: []uint) => (c: uint) {
|
||||
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
|
||||
zi, cc := bits.Add(x[i], y[i], c)
|
||||
z[i] = zi
|
||||
c = cc
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func subVV(z, x, y: []uint) => (c: uint) {
|
||||
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
|
||||
zi, cc := bits.Sub(x[i], y[i], c)
|
||||
z[i] = zi
|
||||
c = cc
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVW(z, x: []uint, y: uint) => (c: uint) {
|
||||
c = y
|
||||
for i := 0; i < len(z) && i < len(x); i++ {
|
||||
zi, cc := bits.Add(x[i], c, 0)
|
||||
z[i] = zi
|
||||
c = cc
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subVW(z, x: []uint, y: uint) => (c: uint) {
|
||||
c = y
|
||||
for i := 0; i < len(z) && i < len(x); i++ {
|
||||
zi, cc := bits.Sub(x[i], c, 0)
|
||||
z[i] = zi
|
||||
c = cc
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shlVU(z, x: []uint, s: uint) => (c: uint) {
|
||||
if s == 0 {
|
||||
copy(z, x)
|
||||
return
|
||||
}
|
||||
if len(z) == 0 {
|
||||
return
|
||||
}
|
||||
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
|
||||
ŝ := _W - s
|
||||
ŝ &= _W - 1 // ditto
|
||||
c = x[len(z)-1] >> ŝ
|
||||
for i := len(z) - 1; i > 0; i-- {
|
||||
z[i] = x[i]<<s | x[i-1]>>ŝ
|
||||
}
|
||||
z[0] = x[0] << s
|
||||
return
|
||||
}
|
||||
|
||||
func shrVU(z, x: []uint, s: uint) => (c: uint) {
|
||||
if s == 0 {
|
||||
copy(z, x)
|
||||
return
|
||||
}
|
||||
if len(z) == 0 {
|
||||
return
|
||||
}
|
||||
if len(x) != len(z) {
|
||||
// This is an invariant guaranteed by the caller.
|
||||
panic("len(x) != len(z)")
|
||||
}
|
||||
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
|
||||
ŝ := _W - s
|
||||
ŝ &= _W - 1 // ditto
|
||||
c = x[0] << ŝ
|
||||
for i := 1; i < len(z); i++ {
|
||||
z[i-1] = x[i-1]>>s | x[i]<<ŝ
|
||||
}
|
||||
z[len(z)-1] = x[len(z)-1] >> s
|
||||
return
|
||||
}
|
||||
|
||||
func mulAddVWW(z, x: []uint, y, r: uint) => (c: uint) {
|
||||
c = r
|
||||
for i := 0; i < len(z) && i < len(x); i++ {
|
||||
c, z[i] = mulAddWWW(x[i], y, c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func addMulVVW(z, x: []uint, y: uint) => (c: uint) {
|
||||
for i := 0; i < len(z) && i < len(x); i++ {
|
||||
z1, z0 := mulAddWWW(x[i], y, z[i])
|
||||
lo, cc := bits.Add(z0, c, 0)
|
||||
c, z[i] = cc, lo
|
||||
c += z1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// q = ( x1 << _W + x0 - r)/y. m = floor(( _B^2 - 1 ) / d - _B). Requiring x1<y.
|
||||
// An approximate reciprocal with a reference to "Improved Division by Invariant Integers
|
||||
// (IEEE Transactions on Computers, 11 Jun. 2010)"
|
||||
func divWW(x1, x0, y, m: uint) => (q, r: uint) {
|
||||
s := nlz(y)
|
||||
if s != 0 {
|
||||
x1 = x1<<s | x0>>(_W-s)
|
||||
x0 <<= s
|
||||
y <<= s
|
||||
}
|
||||
d := y
|
||||
// We know that
|
||||
// m = ⎣(B^2-1)/d⎦-B
|
||||
// ⎣(B^2-1)/d⎦ = m+B
|
||||
// (B^2-1)/d = m+B+delta1 0 <= delta1 <= (d-1)/d
|
||||
// B^2/d = m+B+delta2 0 <= delta2 <= 1
|
||||
// The quotient we're trying to compute is
|
||||
// quotient = ⎣(x1*B+x0)/d⎦
|
||||
// = ⎣(x1*B*(B^2/d)+x0*(B^2/d))/B^2⎦
|
||||
// = ⎣(x1*B*(m+B+delta2)+x0*(m+B+delta2))/B^2⎦
|
||||
// = ⎣(x1*m+x1*B+x0)/B + x0*m/B^2 + delta2*(x1*B+x0)/B^2⎦
|
||||
// The latter two terms of this three-term sum are between 0 and 1.
|
||||
// So we can compute just the first term, and we will be low by at most 2.
|
||||
t1, t0 := bits.Mul(m, x1)
|
||||
_, c := bits.Add(t0, x0, 0)
|
||||
t1, _ = bits.Add(t1, x1, c)
|
||||
// The quotient is either t1, t1+1, or t1+2.
|
||||
// We'll try t1 and adjust if needed.
|
||||
qq := t1
|
||||
// compute remainder r=x-d*q.
|
||||
dq1, dq0 := bits.Mul(d, qq)
|
||||
r0, b := bits.Sub(x0, dq0, 0)
|
||||
r1, _ := bits.Sub(x1, dq1, b)
|
||||
// The remainder we just computed is bounded above by B+d:
|
||||
// r = x1*B + x0 - d*q.
|
||||
// = x1*B + x0 - d*⎣(x1*m+x1*B+x0)/B⎦
|
||||
// = x1*B + x0 - d*((x1*m+x1*B+x0)/B-alpha) 0 <= alpha < 1
|
||||
// = x1*B + x0 - x1*d/B*m - x1*d - x0*d/B + d*alpha
|
||||
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
|
||||
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
|
||||
// = x1*B + x0 - x1*d/B*((B^2-1)/d-B-beta) - x1*d - x0*d/B + d*alpha 0 <= beta < 1
|
||||
// = x1*B + x0 - x1*B + x1/B + x1*d + x1*d/B*beta - x1*d - x0*d/B + d*alpha
|
||||
// = x0 + x1/B + x1*d/B*beta - x0*d/B + d*alpha
|
||||
// = x0*(1-d/B) + x1*(1+d*beta)/B + d*alpha
|
||||
// < B*(1-d/B) + d*B/B + d because x0<B (and 1-d/B>0), x1<d, 1+d*beta<=B, alpha<1
|
||||
// = B - d + d + d
|
||||
// = B+d
|
||||
// So r1 can only be 0 or 1. If r1 is 1, then we know q was too small.
|
||||
// Add 1 to q and subtract d from r. That guarantees that r is <B, so
|
||||
// we no longer need to keep track of r1.
|
||||
if r1 != 0 {
|
||||
qq++
|
||||
r0 -= d
|
||||
}
|
||||
// If the remainder is still too large, increment q one more time.
|
||||
if r0 >= d {
|
||||
qq++
|
||||
r0 -= d
|
||||
}
|
||||
return qq, r0 >> s
|
||||
}
|
||||
|
||||
// reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1).
|
||||
func reciprocalWord(d1: uint) => uint {
|
||||
u := uint(d1 << nlz(d1))
|
||||
x1 := ^u
|
||||
x0 := uint(_M)
|
||||
rec, _ := bits.Div(x1, x0, u) // (_B^2-1)/U-_B = (_B*(_M-C)+_M)/U
|
||||
return uint(rec)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
// 暂时把go的大端转换代码copy过来
|
||||
|
||||
func Buf2Uint64(b: []byte) => uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
func Buf2Uint32(b: []byte) => uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
type Int struct {
|
||||
neg: bool // sign
|
||||
abs: nat // absolute value of the integer
|
||||
}
|
||||
|
||||
var intOne = &Int{false, natOne}
|
||||
|
||||
// 测试用
|
||||
func NewInt(x: string) => *Int {
|
||||
t := new(Int)
|
||||
neg := false
|
||||
if x[0] == '-' {
|
||||
neg = true
|
||||
x = x[1:]
|
||||
}
|
||||
t.abs = natFromString(x)
|
||||
t.neg = neg
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if x < 0
|
||||
// 0 if x == 0
|
||||
// +1 if x > 0
|
||||
//
|
||||
func Int.Sign() => int {
|
||||
if len(this.abs.Data) == 0 {
|
||||
return 0
|
||||
}
|
||||
if this.neg {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// Set sets z to x and returns z.
|
||||
func Int.Set(x: *Int) => *Int {
|
||||
if this != x {
|
||||
this.abs = this.abs.set(x.abs)
|
||||
this.neg = x.neg
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
// 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 Int.Bits() => []uint {
|
||||
return this.abs.Data
|
||||
}
|
||||
|
||||
// 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 Int.SetBits(abs: []uint) => *Int {
|
||||
temp := &nat{abs}
|
||||
this.abs = temp.norm()
|
||||
this.neg = false
|
||||
return this
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func Int.Abs(x: *Int) => *Int {
|
||||
this.Set(x)
|
||||
this.neg = false
|
||||
return this
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func Int.Neg(x: *Int) => *Int {
|
||||
this.Set(x)
|
||||
this.neg = len(this.abs.Data) > 0 && !this.neg // 0 has no sign
|
||||
return this
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func Int.Add(x, y: *Int) => *Int {
|
||||
neg := x.neg
|
||||
if x.neg == y.neg {
|
||||
// x + y == x + y
|
||||
// (-x) + (-y) == -(x + y)
|
||||
this.abs = this.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 {
|
||||
this.abs = this.abs.sub(x.abs, y.abs)
|
||||
} else {
|
||||
neg = !neg
|
||||
this.abs = this.abs.sub(y.abs, x.abs)
|
||||
}
|
||||
}
|
||||
this.neg = len(this.abs.Data) > 0 && neg // 0 has no sign
|
||||
return this
|
||||
}
|
||||
|
||||
// Sub sets z to the difference x-y and returns z.
|
||||
func Int.Sub(x, y: *Int) => *Int {
|
||||
neg := x.neg
|
||||
if x.neg != y.neg {
|
||||
// x - (-y) == x + y
|
||||
// (-x) - y == -(x + y)
|
||||
this.abs = this.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 {
|
||||
this.abs = this.abs.sub(x.abs, y.abs)
|
||||
} else {
|
||||
neg = !neg
|
||||
this.abs = this.abs.sub(y.abs, x.abs)
|
||||
}
|
||||
}
|
||||
this.neg = len(this.abs.Data) > 0 && neg // 0 has no sign
|
||||
return this
|
||||
}
|
||||
|
||||
// Mul sets z to the product x*y and returns z.
|
||||
func Int.Mul(x, y: *Int) => *Int {
|
||||
// x * y == x * y
|
||||
// x * (-y) == -(x * y)
|
||||
// (-x) * y == -(x * y)
|
||||
// (-x) * (-y) == x * y
|
||||
this.abs = this.abs.mul(x.abs, y.abs)
|
||||
this.neg = len(this.abs.Data) > 0 && this.neg != this.neg // 0 has no sign
|
||||
return this
|
||||
}
|
||||
|
||||
// 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 Int.QuoRem(x, y, r: *Int) => (*Int, *Int) {
|
||||
this.abs, r.abs = this.abs.div(r.abs, x.abs, y.abs)
|
||||
this.neg, r.neg = len(this.abs.Data) > 0 && x.neg != y.neg, len(r.abs.Data) > 0 && x.neg // 0 has no sign
|
||||
return this, r
|
||||
}
|
||||
|
||||
// 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 < |y|
|
||||
//
|
||||
// (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 Int.DivMod(x, y, m: *Int) => (*Int, *Int) {
|
||||
y0 := y // save y
|
||||
if this == y || alias(this.abs, y.abs) {
|
||||
y0 = new(Int).Set(y)
|
||||
}
|
||||
this.QuoRem(x, y, m)
|
||||
if m.neg {
|
||||
if y0.neg {
|
||||
this.Add(this, intOne)
|
||||
m.Sub(m, y0)
|
||||
} else {
|
||||
this.Sub(this, intOne)
|
||||
m.Add(m, y0)
|
||||
}
|
||||
}
|
||||
return this, m
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
//
|
||||
func 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 this == y:
|
||||
// nothing to do
|
||||
case this.neg == y.neg:
|
||||
r = this.abs.cmp(y.abs)
|
||||
if this.neg {
|
||||
r = -r
|
||||
}
|
||||
case this.neg:
|
||||
r = -1
|
||||
default:
|
||||
r = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CmpAbs compares the absolute values of x and y and returns:
|
||||
//
|
||||
// -1 if |x| < |y|
|
||||
// 0 if |x| == |y|
|
||||
// +1 if |x| > |y|
|
||||
//
|
||||
func Int.CmpAbs(y: *Int) => int {
|
||||
return this.abs.cmp(y.abs)
|
||||
}
|
||||
|
||||
// SetBytes interprets buf as the bytes of a big-endian unsigned
|
||||
// integer, sets z to that value, and returns z.
|
||||
func Int.SetBytes(buf: []byte) => *Int {
|
||||
this.abs = this.abs.setBytes(buf)
|
||||
this.neg = false
|
||||
return this
|
||||
}
|
||||
|
||||
// Bytes returns the absolute value of x as a big-endian byte slice.
|
||||
//
|
||||
// To use a fixed length slice, or a preallocated one, use FillBytes.
|
||||
func Int.Bytes() => []byte {
|
||||
buf := make([]byte, len(this.abs.Data)*_S)
|
||||
return buf[this.abs.bytes(buf):]
|
||||
}
|
||||
|
||||
// BitLen returns the length of the absolute value of x in bits.
|
||||
// The bit length of 0 is 0.
|
||||
func Int.BitLen() => int {
|
||||
return this.abs.bitLen()
|
||||
}
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
type nat struct {
|
||||
Data: []uint
|
||||
}
|
||||
|
||||
func natFromString(s: string) => nat {
|
||||
temp := &nat{nil}
|
||||
return temp.setString(s)
|
||||
}
|
||||
|
||||
// 这个方法是临时使用的, 用于部分内容的测试
|
||||
func nat.setString(s: string) => nat {
|
||||
// 长度应该是超过的
|
||||
z := this.make((len(s) + _S - 1) / _S)
|
||||
val: uint = 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] < '0' || s[i] > '9' {
|
||||
println("bad big integer:", s[i])
|
||||
}
|
||||
val = uint(s[i] - '0')
|
||||
z = z.mulAddWW(z, 10, val)
|
||||
val = 0
|
||||
}
|
||||
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
func nat.clear() {
|
||||
for i := range this.Data {
|
||||
this.Data[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
natOne = nat{Data: []uint{1}}
|
||||
)
|
||||
|
||||
func nat.raw_print() {
|
||||
print("raw_nat: {")
|
||||
for i := range this.Data {
|
||||
print(this.Data[i])
|
||||
if i != len(this.Data)-1 {
|
||||
print(",")
|
||||
}
|
||||
}
|
||||
println("}")
|
||||
}
|
||||
|
||||
func nat.norm() => nat {
|
||||
i := len(this.Data)
|
||||
for i > 0 && this.Data[i-1] == 0 {
|
||||
i--
|
||||
}
|
||||
return nat{Data: this.Data[0:i]}
|
||||
}
|
||||
|
||||
func nat.make(n: int) => nat {
|
||||
if n <= cap(this.Data) {
|
||||
return nat{Data: this.Data[:n]} // reuse this.Data
|
||||
}
|
||||
if n == 1 {
|
||||
// Most nats start small and stay that way; don't over-allocate.
|
||||
return nat{Data: make([]uint, 1)}
|
||||
}
|
||||
// Choosing a good value for e has significant performance impact
|
||||
// because it increases the chance that a value can be reused.
|
||||
const e = 4 // extra capacity
|
||||
return nat{Data: make([]uint, n, n+e)}
|
||||
}
|
||||
|
||||
func nat.setWord(x: uint) => nat {
|
||||
if x == 0 {
|
||||
return nat{Data: this.Data[:0]}
|
||||
}
|
||||
z := this.make(1)
|
||||
z.Data[0] = x
|
||||
return z
|
||||
}
|
||||
|
||||
func nat.set(x: nat) => nat {
|
||||
z := this.make(len(x.Data))
|
||||
copy(z.Data, x.Data)
|
||||
|
||||
return z
|
||||
}
|
||||
|
||||
func nat.add(x, y: nat) => nat {
|
||||
m := len(x.Data)
|
||||
n := len(y.Data)
|
||||
|
||||
switch {
|
||||
case m < n:
|
||||
return this.add(y, x)
|
||||
case m == 0:
|
||||
// n == 0 because m >= n; result is 0
|
||||
return nat{Data: this.Data[:0]}
|
||||
case n == 0:
|
||||
// result is x
|
||||
return this.set(x)
|
||||
}
|
||||
// m > 0
|
||||
z := this.make(m + 1)
|
||||
c := addVV(z.Data[0:n], x.Data, y.Data)
|
||||
if m > n {
|
||||
c = addVW(z.Data[n:m], x.Data[n:], c)
|
||||
}
|
||||
z.Data[m] = c
|
||||
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
func nat.sub(x, y: nat) => nat {
|
||||
m := len(x.Data)
|
||||
n := len(y.Data)
|
||||
switch {
|
||||
case m < n:
|
||||
panic("underflow")
|
||||
case m == 0:
|
||||
// n == 0 because m >= n; result is 0
|
||||
return nat{Data: this.Data[:0]}
|
||||
case n == 0:
|
||||
// result is x
|
||||
return this.set(x)
|
||||
}
|
||||
// m > 0
|
||||
z := this.make(m)
|
||||
c := subVV(z.Data[0:n], x.Data, y.Data)
|
||||
if m > n {
|
||||
c = subVW(z.Data[n:], x.Data[n:], c)
|
||||
}
|
||||
if c != 0 {
|
||||
panic("underflow")
|
||||
}
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
func nat.cmp(y: nat) => int {
|
||||
r := 0
|
||||
m := len(this.Data)
|
||||
n := len(y.Data)
|
||||
if m != n || m == 0 {
|
||||
switch {
|
||||
case m < n:
|
||||
r = -1
|
||||
case m > n:
|
||||
r = 1
|
||||
}
|
||||
return r
|
||||
}
|
||||
i := m - 1
|
||||
for i > 0 && this.Data[i] == y.Data[i] {
|
||||
i--
|
||||
}
|
||||
switch {
|
||||
case this.Data[i] < y.Data[i]:
|
||||
r = -1
|
||||
case this.Data[i] > y.Data[i]:
|
||||
r = 1
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func nat.mulAddWW(x: nat, y, r: uint) => nat {
|
||||
m := len(x.Data)
|
||||
if m == 0 || y == 0 {
|
||||
return this.setWord(r) // result is r
|
||||
}
|
||||
// m > 0
|
||||
|
||||
z := this.make(m + 1)
|
||||
z.Data[m] = mulAddVWW(z.Data[:m], x.Data, y, r)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// basicMul multiplies x and y and leaves the result in z.
|
||||
// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
|
||||
func basicMul(z, x, y: nat) {
|
||||
// z.Data[:len(x.Data)+len(y.Data)].clear()
|
||||
// initialize z
|
||||
t := nat{Data: z.Data[:len(x.Data)+len(y.Data)]}
|
||||
t.clear()
|
||||
|
||||
for i, d := range y.Data {
|
||||
if d != 0 {
|
||||
z.Data[len(x.Data)+i] = addMulVVW(z.Data[i:i+len(x.Data)], x.Data, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// alias reports whether x and y share the same base array.
|
||||
// Note: alias assumes that the capacity of underlying arrays
|
||||
// is never changed for nat values; i.e. that there are
|
||||
// no 3-operand slice expressions in this code (or worse,
|
||||
// reflect-based operations to the same effect).
|
||||
func alias(x, y: nat) => bool {
|
||||
x_cap := cap(x.Data)
|
||||
y_cap := cap(y.Data)
|
||||
return x_cap > 0 && y_cap > 0 && &x.Data[:x_cap][x_cap-1] == &y.Data[:y_cap][y_cap-1]
|
||||
}
|
||||
|
||||
// addAt implements z += x<<(_W*i); z must be long enough.
|
||||
// (we don't use nat.add because we need z to stay the same
|
||||
// slice, and we don't need to normalize z after each addition)
|
||||
func addAt(z, x: nat, i: int) {
|
||||
if n := len(x.Data); n > 0 {
|
||||
if c := addVV(z.Data[i:i+n], z.Data[i:], x.Data); c != 0 {
|
||||
j := i + n
|
||||
if j < len(z.Data) {
|
||||
addVW(z.Data[j:], z.Data[j:], c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nat.mul(x, y: nat) => nat {
|
||||
m := len(x.Data)
|
||||
n := len(y.Data)
|
||||
switch {
|
||||
case m < n:
|
||||
return this.mul(y, x)
|
||||
case m == 0 || n == 0:
|
||||
return nat{Data: this.Data[:0]}
|
||||
case n == 1:
|
||||
return this.mulAddWW(x, y.Data[0], 0)
|
||||
}
|
||||
// m >= n > 1
|
||||
|
||||
// determine if z can be reused
|
||||
if alias(*this, x) || alias(*this, y) {
|
||||
// 空指针操作
|
||||
this = nil // z is an alias for x or y - cannot reuse
|
||||
}
|
||||
|
||||
z := this.make(m + n)
|
||||
basicMul(z, x, y)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
func getNat(n: int) => *nat {
|
||||
r := (&nat{}).make(n)
|
||||
return &r
|
||||
}
|
||||
|
||||
func putNat(x: *nat) {
|
||||
// panic("todo")
|
||||
}
|
||||
|
||||
func nat.bitLen() => int {
|
||||
if i := len(this.Data) - 1; i >= 0 {
|
||||
return i*_W + bits.Len(uint(this.Data[i]))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// bytes writes the value of z into buf using big-endian encoding.
|
||||
// The value of z is encoded in the slice buf[i:]. If the value of z
|
||||
// cannot be represented in buf, bytes panics. The number i of unused
|
||||
// bytes at the beginning of buf is returned as result.
|
||||
func nat.bytes(buf: []byte) => int {
|
||||
i := len(buf)
|
||||
for _, d := range this.Data {
|
||||
for j := 0; j < _S; j++ {
|
||||
i--
|
||||
if i >= 0 {
|
||||
buf[i] = byte(d)
|
||||
} else if byte(d) != 0 {
|
||||
panic("math/big: buffer too small to fit value")
|
||||
}
|
||||
d >>= 8
|
||||
}
|
||||
}
|
||||
|
||||
if i < 0 {
|
||||
i = 0
|
||||
}
|
||||
for i < len(buf) && buf[i] == 0 {
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// bigEndianWord returns the contents of buf interpreted as a big-endian encoded Word value.
|
||||
func bigEndianWord(buf: []byte) => uint {
|
||||
if _W == 64 {
|
||||
return uint(Buf2Uint64(buf))
|
||||
}
|
||||
return uint(Buf2Uint64(buf))
|
||||
}
|
||||
|
||||
// setBytes interprets buf as the bytes of a big-endian unsigned
|
||||
// integer, sets z to that value, and returns z.
|
||||
func nat.setBytes(buf: []byte) => nat {
|
||||
z := this.make((len(buf) + _S - 1) / _S)
|
||||
i := len(buf)
|
||||
for k := 0; i >= _S; k++ {
|
||||
z.Data[k] = bigEndianWord(buf[i-_S : i])
|
||||
i -= _S
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
d: uint = 0
|
||||
for s := uint(0); i > 0; s += 8 {
|
||||
d |= uint(buf[i-1]) << s
|
||||
i--
|
||||
}
|
||||
z.Data[len(z.Data)-1] = d
|
||||
}
|
||||
|
||||
return z.norm()
|
||||
}
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
// Author: TrueAbc
|
||||
// Note:
|
||||
// The implementation refers to the go language "math/big" lib.
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// div returns q, r such that q = ⌊u/v⌋ and r = u%v = u - q·v.
|
||||
// It uses z and z2 as the storage for q and r.
|
||||
func nat.div(z2, u, v: nat) => (q: nat, r: nat) {
|
||||
if len(v.Data) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
|
||||
if u.cmp(v) < 0 {
|
||||
q.Data = this.Data[:0]
|
||||
r = z2.set(u)
|
||||
return
|
||||
}
|
||||
if len(v.Data) == 1 {
|
||||
// Short division: long optimized for a single-word divisor.
|
||||
// In that case, the 2-by-1 guess is all we need at each step.
|
||||
r2: uint
|
||||
q, r2 = this.divW(u, v.Data[0])
|
||||
r = z2.setWord(r2)
|
||||
return
|
||||
}
|
||||
q, r = this.divLarge(z2, u, v)
|
||||
return
|
||||
}
|
||||
|
||||
func nat.divW(x: nat, y: uint) => (q: nat, r: uint) {
|
||||
m := len(x.Data)
|
||||
switch {
|
||||
case y == 0:
|
||||
panic("division by zero")
|
||||
case y == 1:
|
||||
q = this.set(x) // result is x
|
||||
return
|
||||
case m == 0:
|
||||
q.Data = this.Data[:0] // result is 0
|
||||
return
|
||||
}
|
||||
// m > 0
|
||||
z := this.make(m)
|
||||
r = divWVW(z.Data, 0, x.Data, y)
|
||||
q = z.norm()
|
||||
return
|
||||
}
|
||||
|
||||
// divWVW overwrites z with ⌊x/y⌋, returning the remainder r.
|
||||
// The caller must ensure that len(z) = len(x).
|
||||
func divWVW(z: []uint, xn: uint, x: []uint, y: uint) => (r: uint) {
|
||||
r = xn
|
||||
if len(x) == 1 {
|
||||
qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
|
||||
z[0] = uint(qq)
|
||||
return uint(rr)
|
||||
}
|
||||
|
||||
rec := reciprocalWord(y)
|
||||
for i := len(z) - 1; i >= 0; i-- {
|
||||
z[i], r = divWW(r, x[i], y, rec)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// div returns q, r such that q = ⌊uIn/vIn⌋ and r = uIn%vIn = uIn - q·vIn.
|
||||
// It uses z and u as the storage for q and r.
|
||||
// The caller must ensure that len(vIn) ≥ 2 (use divW otherwise)
|
||||
// and that len(uIn) ≥ len(vIn) (the answer is 0, uIn otherwise).
|
||||
func nat.divLarge(u, uIn, vIn: nat) => (q: nat, r: nat) {
|
||||
z := *this
|
||||
n := len(vIn.Data)
|
||||
m := len(uIn.Data) - n
|
||||
// Scale the inputs so vIn's top bit is 1 (see “Scaling Inputs” above).
|
||||
// vIn is treated as a read-only input (it may be in use by another
|
||||
// goroutine), so we must make a copy.
|
||||
shift := nlz(vIn.Data[n-1])
|
||||
vp := getNat(n)
|
||||
v := *vp
|
||||
shlVU(v.Data, vIn.Data, shift)
|
||||
u = u.make(len(uIn.Data) + 1)
|
||||
u.Data[len(uIn.Data)] = shlVU(u.Data[0:len(uIn.Data)], uIn.Data, shift)
|
||||
|
||||
// The caller should not pass aliased z and u, since those are
|
||||
// the two different outputs, but correct just in case.
|
||||
if alias(z, u) {
|
||||
z.Data = nil
|
||||
}
|
||||
q = z.make(m + 1)
|
||||
|
||||
// Use basic or recursive long division depending on size.
|
||||
if n < divRecursiveThreshold {
|
||||
q.divBasic(u, v)
|
||||
} else {
|
||||
q.divRecursive(u, v)
|
||||
}
|
||||
putNat(vp)
|
||||
|
||||
q = q.norm()
|
||||
|
||||
// Undo scaling of remainder.
|
||||
shrVU(u.Data, u.Data, shift)
|
||||
r = u.norm()
|
||||
|
||||
return q, r
|
||||
}
|
||||
|
||||
// divBasic implements long division as described above.
|
||||
// It overwrites q with ⌊u/v⌋ and overwrites u with the remainder r.
|
||||
// q must be large enough to hold ⌊u/v⌋.
|
||||
func nat.divBasic(u, v: nat) {
|
||||
n := len(v.Data)
|
||||
m := len(u.Data) - n
|
||||
|
||||
qhatvp := getNat(n + 1)
|
||||
qhatv := *qhatvp
|
||||
|
||||
// Set up for divWW below, precomputing reciprocal argument.
|
||||
vn1 := v.Data[n-1]
|
||||
rec := reciprocalWord(vn1)
|
||||
|
||||
// Compute each digit of quotient.
|
||||
for j := m; j >= 0; j-- {
|
||||
// Compute the 2-by-1 guess q̂.
|
||||
// The first iteration must invent a leading 0 for u.
|
||||
qhat := uint(_M)
|
||||
ujn: uint
|
||||
if j+n < len(u.Data) {
|
||||
ujn = u.Data[j+n]
|
||||
}
|
||||
|
||||
// ujn ≤ vn1, or else q̂ would be more than one digit.
|
||||
// For ujn == vn1, we set q̂ to the max digit M above.
|
||||
// Otherwise, we compute the 2-by-1 guess.
|
||||
if ujn != vn1 {
|
||||
rhat: uint
|
||||
qhat, rhat = divWW(ujn, u.Data[j+n-1], vn1, rec)
|
||||
|
||||
// Refine q̂ to a 3-by-2 guess. See “Refining Guesses” above.
|
||||
vn2 := v.Data[n-2]
|
||||
x1, x2 := mulWW(qhat, vn2)
|
||||
ujn2 := u.Data[j+n-2]
|
||||
for greaterThan(x1, x2, rhat, ujn2) {
|
||||
qhat--
|
||||
prevRhat := rhat
|
||||
rhat += vn1
|
||||
// If r̂ overflows, then
|
||||
// r̂ u[j+n-2]v[n-1] is now definitely > x1 x2.
|
||||
if rhat < prevRhat {
|
||||
break
|
||||
}
|
||||
// TODO(rsc): No need for a full mulWW.
|
||||
// x2 += vn2; if x2 overflows, x1++
|
||||
x1, x2 = mulWW(qhat, vn2)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute q̂·v.
|
||||
qhatv.Data[n] = mulAddVWW(qhatv.Data[0:n], v.Data, qhat, 0)
|
||||
qhl := len(qhatv.Data)
|
||||
if j+qhl > len(u.Data) && qhatv.Data[n] == 0 {
|
||||
qhl--
|
||||
}
|
||||
|
||||
// Subtract q̂·v from the current section of u.
|
||||
// If it underflows, q̂·v > u, which we fix up
|
||||
// by decrementing q̂ and adding v back.
|
||||
c := subVV(u.Data[j:j+qhl], u.Data[j:], qhatv.Data)
|
||||
if c != 0 {
|
||||
c := addVV(u.Data[j:j+n], u.Data[j:], v.Data)
|
||||
// If n == qhl, the carry from subVV and the carry from addVV
|
||||
// cancel out and don't affect u[j+n].
|
||||
if n < qhl {
|
||||
u.Data[j+n] += c
|
||||
}
|
||||
qhat--
|
||||
}
|
||||
|
||||
// Save quotient digit.
|
||||
// Caller may know the top digit is zero and not leave room for it.
|
||||
if j == m && m == len(this.Data) && qhat == 0 {
|
||||
continue
|
||||
}
|
||||
this.Data[j] = qhat
|
||||
}
|
||||
|
||||
putNat(qhatvp)
|
||||
}
|
||||
|
||||
// greaterThan reports whether the two digit numbers x1 x2 > y1 y2.
|
||||
// TODO(rsc): In contradiction to most of this file, x1 is the high
|
||||
// digit and x2 is the low digit. This should be fixed.
|
||||
func greaterThan(x1, x2, y1, y2: uint) => bool {
|
||||
return x1 > y1 || x1 == y1 && x2 > y2
|
||||
}
|
||||
|
||||
// divRecursiveThreshold is the number of divisor digits
|
||||
// at which point divRecursive is faster than divBasic.
|
||||
const divRecursiveThreshold = 100
|
||||
|
||||
// divRecursive implements recursive division as described above.
|
||||
// It overwrites z with ⌊u/v⌋ and overwrites u with the remainder r.
|
||||
// z must be large enough to hold ⌊u/v⌋.
|
||||
// This function is just for allocating and freeing temporaries
|
||||
// around divRecursiveStep, the real implementation.
|
||||
func nat.divRecursive(u, v: nat) {
|
||||
// Recursion depth is (much) less than 2 log₂(len(v)).
|
||||
// Allocate a slice of temporaries to be reused across recursion,
|
||||
// plus one extra temporary not live across the recursion.
|
||||
recDepth := 2 * bits.Len(uint(len(v.Data)))
|
||||
tmp := getNat(3 * len(v.Data))
|
||||
|
||||
temps := make([]*nat, recDepth)
|
||||
|
||||
this.clear()
|
||||
this.divRecursiveStep(u, v, 0, tmp, temps)
|
||||
// Free temporaries.
|
||||
for _, n := range temps {
|
||||
if n != nil {
|
||||
putNat(n)
|
||||
}
|
||||
}
|
||||
putNat(tmp)
|
||||
}
|
||||
|
||||
// divRecursiveStep is the actual implementation of recursive division.
|
||||
// It adds ⌊u/v⌋ to z and overwrites u with the remainder r.
|
||||
// z must be large enough to hold ⌊u/v⌋.
|
||||
// It uses temps[depth] (allocating if needed) as a temporary live across
|
||||
// the recursive call. It also uses tmp, but not live across the recursion.
|
||||
func nat.divRecursiveStep(u, v: nat, depth: int, tmp: *nat, temps: []*nat) {
|
||||
// u is a subsection of the original and may have leading zeros.
|
||||
// TODO(rsc): The v = v.norm() is useless and should be removed.
|
||||
// We know (and require) that v's top digit is ≥ B/2.
|
||||
u = u.norm()
|
||||
v = v.norm()
|
||||
if len(u.Data) == 0 {
|
||||
this.clear()
|
||||
return
|
||||
}
|
||||
|
||||
// Fall back to basic division if the problem is now small enough.
|
||||
n := len(v.Data)
|
||||
if n < divRecursiveThreshold {
|
||||
this.divBasic(u, v)
|
||||
return
|
||||
}
|
||||
|
||||
// Nothing to do if u is shorter than v (implies u < v).
|
||||
m := len(u.Data) - n
|
||||
if m < 0 {
|
||||
return
|
||||
}
|
||||
// We consider B digits in a row as a single wide digit.
|
||||
// (See “Recursive Division” above.)
|
||||
//
|
||||
// TODO(rsc): rename B to Wide, to avoid confusion with _B,
|
||||
// which is something entirely different.
|
||||
// TODO(rsc): Look into whether using ⌈n/2⌉ is better than ⌊n/2⌋.
|
||||
B := n / 2
|
||||
|
||||
// Allocate a nat for qhat below.
|
||||
if temps[depth] == nil {
|
||||
temps[depth] = getNat(n) // TODO(rsc): Can be just B+1.
|
||||
} else {
|
||||
*temps[depth] = temps[depth].make(B + 1)
|
||||
}
|
||||
|
||||
// Compute each wide digit of the quotient.
|
||||
//
|
||||
// TODO(rsc): Change the loop to be
|
||||
// for j := (m+B-1)/B*B; j > 0; j -= B {
|
||||
// which will make the final step a regular step, letting us
|
||||
// delete what amounts to an extra copy of the loop body below.
|
||||
j := m
|
||||
|
||||
for j > B {
|
||||
// Divide u[j-B:j+n] (3 wide digits) by v (2 wide digits).
|
||||
// First make the 2-by-1-wide-digit guess using a recursive call.
|
||||
// Then extend the guess to the full 3-by-2 (see “Refining Guesses”).
|
||||
//
|
||||
// For the 2-by-1-wide-digit guess, instead of doing 2B-by-B-digit,
|
||||
// we use a (2B+1)-by-(B+1) digit, which handles the possibility that
|
||||
// the result has an extra leading 1 digit as well as guaranteeing
|
||||
// that the computed q̂ will be off by at most 1 instead of 2.
|
||||
|
||||
// s is the number of digits to drop from the 3B- and 2B-digit chunks.
|
||||
// We drop B-1 to be left with 2B+1 and B+1.
|
||||
s := (B - 1)
|
||||
|
||||
// uu is the up-to-3B-digit section of u we are working on.
|
||||
uu := nat{u.Data[j-B:]}
|
||||
|
||||
// Compute the 2-by-1 guess q̂, leaving r̂ in uu[s:B+n].
|
||||
qhat := *temps[depth]
|
||||
qhat.clear()
|
||||
qhat.divRecursiveStep(nat{uu.Data[s : B+n]}, nat{v.Data[s:]}, depth+1, tmp, temps)
|
||||
qhat = qhat.norm()
|
||||
|
||||
// Extend to a 3-by-2 quotient and remainder.
|
||||
// Because divRecursiveStep overwrote the top part of uu with
|
||||
// the remainder r̂, the full uu already contains the equivalent
|
||||
// of r̂·B + uₙ₋₂ from the “Refining Guesses” discussion.
|
||||
// Subtracting q̂·vₙ₋₂ from it will compute the full-length remainder.
|
||||
// If that subtraction underflows, q̂·v > u, which we fix up
|
||||
// by decrementing q̂ and adding v back, same as in long division.
|
||||
|
||||
// TODO(rsc): Instead of subtract and fix-up, this code is computing
|
||||
// q̂·vₙ₋₂ and decrementing q̂ until that product is ≤ u.
|
||||
// But we can do the subtraction directly, as in the comment above
|
||||
// and in long division, because we know that q̂ is wrong by at most one.
|
||||
qhatv := tmp.make(3 * n)
|
||||
qhatv.clear()
|
||||
qhatv = qhatv.mul(qhat, nat{v.Data[:s]})
|
||||
for i := 0; i < 2; i++ {
|
||||
e := qhatv.cmp(uu.norm())
|
||||
if e <= 0 {
|
||||
break
|
||||
}
|
||||
subVW(qhat.Data, qhat.Data, 1)
|
||||
c := subVV(qhatv.Data[:s], qhatv.Data[:s], v.Data[:s])
|
||||
if len(qhatv.Data) > s {
|
||||
subVW(qhatv.Data[s:], qhatv.Data[s:], c)
|
||||
}
|
||||
addAt(nat{uu.Data[s:]}, nat{v.Data[s:]}, 0)
|
||||
}
|
||||
if qhatv.cmp(uu.norm()) > 0 {
|
||||
panic("impossible")
|
||||
}
|
||||
c := subVV(uu.Data[:len(qhatv.Data)], uu.Data[:len(qhatv.Data)], qhatv.Data)
|
||||
if c > 0 {
|
||||
subVW(uu.Data[len(qhatv.Data):], uu.Data[len(qhatv.Data):], c)
|
||||
}
|
||||
addAt(*this, qhat, j-B)
|
||||
j -= B
|
||||
}
|
||||
|
||||
// TODO(rsc): Rewrite loop as described above and delete all this code.
|
||||
|
||||
// Now u < (v<<B), compute lower bits in the same way.
|
||||
// Choose shift = B-1 again.
|
||||
s := B - 1
|
||||
qhat := *temps[depth]
|
||||
qhat.clear()
|
||||
temp_u := &nat{u.Data[s:]}
|
||||
qhat.divRecursiveStep(temp_u.norm(), nat{v.Data[s:]}, depth+1, tmp, temps)
|
||||
qhat = qhat.norm()
|
||||
qhatv := tmp.make(3 * n)
|
||||
qhatv.clear()
|
||||
qhatv = qhatv.mul(qhat, nat{v.Data[:s]})
|
||||
// Set the correct remainder as before.
|
||||
for i := 0; i < 2; i++ {
|
||||
if e := qhatv.cmp(u.norm()); e > 0 {
|
||||
subVW(qhat.Data, qhat.Data, 1)
|
||||
c := subVV(qhatv.Data[:s], qhatv.Data[:s], v.Data[:s])
|
||||
if len(qhatv.Data) > s {
|
||||
subVW(qhatv.Data[s:], qhatv.Data[s:], c)
|
||||
}
|
||||
addAt(nat{u.Data[s:]}, nat{v.Data[s:]}, 0)
|
||||
}
|
||||
}
|
||||
if qhatv.cmp(u.norm()) > 0 {
|
||||
panic("impossible")
|
||||
}
|
||||
c := subVV(u.Data[0:len(qhatv.Data)], u.Data[0:len(qhatv.Data)], qhatv.Data)
|
||||
if c > 0 {
|
||||
c = subVW(u.Data[len(qhatv.Data):], u.Data[len(qhatv.Data):], c)
|
||||
}
|
||||
if c > 0 {
|
||||
panic("impossible")
|
||||
}
|
||||
// Done!
|
||||
addAt(*this, qhat.norm(), 0)
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import "base60/big" //当前目录的包路径为'base60'(在wa.mod.json中配置),因此导入当前目录下的包应添加'base60/'路径前缀
|
||||
|
||||
func main {
|
||||
println("Base60 主程序入口")
|
||||
|
||||
big.AAA()
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wa_bigint_std",
|
||||
"pkgpath": "myapp",
|
||||
"name": "base60",
|
||||
"pkgpath": "base60",
|
||||
"version": "0.0.1",
|
||||
"authors": ["author", "author2"],
|
||||
"description": "module description",
|
||||
|
|
|
|||
Loading…
Reference in New Issue