126 lines
2.3 KiB
Go
126 lines
2.3 KiB
Go
package fpe
|
|
|
|
import (
|
|
"math"
|
|
"math/big"
|
|
"math/bits"
|
|
)
|
|
|
|
type Radix struct {
|
|
r int
|
|
|
|
e int // the maximum number such that r^e is a uint64
|
|
|
|
rBig *big.Int // radix as big
|
|
|
|
reBig *big.Int // radix^e as big.Int, the same as rPowers[-1]
|
|
|
|
rPowers []big.Int // [r, r^2, ..., r^e]
|
|
}
|
|
|
|
func NewRadix(r int) *Radix {
|
|
radix := &Radix{}
|
|
radix.Set(r)
|
|
return radix
|
|
}
|
|
|
|
func (r *Radix) Set(v int) {
|
|
if v < 2 || v >= math.MaxUint16 {
|
|
panic("radix overflow")
|
|
}
|
|
r.r = v
|
|
r.e = 64 / bits.Len32(uint32(v))
|
|
r.rPowers = make([]big.Int, r.e)
|
|
r.rPowers[0].SetUint64(uint64(v))
|
|
for i, vi := 1, uint64(v); i < r.e; i++ {
|
|
vi *= uint64(v)
|
|
r.rPowers[i].SetUint64(vi)
|
|
}
|
|
r.rBig = &r.rPowers[0]
|
|
r.reBig = &r.rPowers[r.e-1]
|
|
}
|
|
|
|
func (r *Radix) Radix() int {
|
|
return r.r
|
|
}
|
|
|
|
func (r *Radix) Num(X []Char) *big.Int {
|
|
if false {
|
|
radix := big.NewInt(int64(r.r))
|
|
n := new(big.Int)
|
|
for _, d := range X {
|
|
n.Mul(n, radix)
|
|
n.Add(n, big.NewInt(int64(d)))
|
|
}
|
|
return n
|
|
} else {
|
|
radix := uint64(r.r)
|
|
l := len(X) % r.e
|
|
|
|
tail := uint64(0)
|
|
for i := 0; i < l; i++ {
|
|
tail *= uint64(radix)
|
|
tail += uint64(X[i])
|
|
}
|
|
|
|
n := new(big.Int).SetUint64(tail)
|
|
for i := l; i < len(X); i += r.e {
|
|
d := uint64(0)
|
|
for j := 0; j < r.e; j++ {
|
|
d = d*uint64(radix) + uint64(X[i+j])
|
|
}
|
|
|
|
n.Mul(n, r.reBig)
|
|
n.Add(n, new(big.Int).SetUint64(d))
|
|
}
|
|
return n
|
|
}
|
|
}
|
|
|
|
// x should < radix^(lenX)
|
|
func (r *Radix) Str(X []Numeral, x *big.Int) {
|
|
if false {
|
|
n := len(X)
|
|
radix := big.NewInt(int64(r.r))
|
|
d := new(big.Int)
|
|
xx := new(big.Int).Set(x) // make a copy
|
|
for i := 0; i < n; i++ {
|
|
xx, d = xx.DivMod(xx, radix, d)
|
|
X[n-i-1] = Numeral(d.Int64())
|
|
}
|
|
// if xx is not zero, then the input x must too big
|
|
if xx.Sign() != 0 {
|
|
panic("x should less then radix^m")
|
|
}
|
|
} else {
|
|
xx := new(big.Int).Set(x) // make a copy
|
|
lx := len(X)
|
|
radix := uint64(r.r)
|
|
d := new(big.Int)
|
|
|
|
// the tail part
|
|
m := lx % r.e
|
|
if m > 0 {
|
|
xx, d = xx.DivMod(xx, &r.rPowers[m-1], d)
|
|
n := d.Uint64()
|
|
for i := lx - 1; i >= lx-m; i-- {
|
|
X[i] = Numeral(n % radix)
|
|
n /= radix
|
|
}
|
|
}
|
|
|
|
for i := lx - m; i > 0; i -= r.e {
|
|
xx, d = xx.DivMod(xx, r.reBig, d)
|
|
n := d.Uint64()
|
|
for j := i - 1; j >= i-r.e; j-- {
|
|
X[j] = uint16(n % radix)
|
|
n /= radix
|
|
}
|
|
}
|
|
// if xx is not zero, then the input x must too big
|
|
if xx.Sign() != 0 {
|
|
panic("x should less then radix^m")
|
|
}
|
|
}
|
|
}
|