Files
xgcl/x/fpe/radix.go
T
2026-05-27 23:03:00 +08:00

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")
}
}
}