geom/primes/factor.go

93 lines
2.1 KiB
Go

package primes
import "math/big"
// Factor represents a factor with a base (Prime) and an exponent (Exponent)
type Factor struct {
Prime int64
Exponent int
}
// Factorize calculates the factors of n and returns it as a slice of Factor's (uses a default cache).
func Factorize(n int64) []Factor {
return FactorizeCache(primes, n)
}
// FactorizeCache calculates the factors of n and returns it as a slice of Factor's and specifies the cache to use.
func FactorizeCache(c Cache, n int64) []Factor {
if 1 > n {
return []Factor{}
}
var factors []Factor
it := NewIteratorFromCache(c)
for it.Next() {
p := it.Get()
var exp int
for n%p == 0 {
n /= p
exp++
}
if 0 < exp {
factors = append(factors, Factor{p, exp})
}
if n < p*p {
break
}
}
if 1 < n {
factors = append(factors, Factor{n, 1})
} else if 1 == n && 0 == len(factors) {
return []Factor{{1, 1}}
}
return factors
}
// MustBigIntToInt64 returns the int64 representation of the big int n. If n is too large the method panics.
func MustBigIntToInt64(n *big.Int) int64 {
if !n.IsInt64() {
panic("n can't be represented as a int64")
}
return n.Int64()
}
// FactorizeBigInt calculates the factors of n and returns it as a slice of Factor's. If the base of a factor is larger than can be represented as a int64 the method will panic.
func FactorizeBigInt(n *big.Int) []Factor {
n = big.NewInt(0).Set(n)
var one = big.NewInt(1)
if one.Cmp(n) > 0 {
return []Factor{}
}
var zero = big.NewInt(0)
var divModZero = func(p *big.Int) bool {
var quo, rem = big.NewInt(0), big.NewInt(0)
quo.QuoRem(n, p, rem)
if rem.Cmp(zero) == 0 {
n = quo
return true
}
return false
}
var factors []Factor
it := NewIterator()
for it.Next() {
var p = big.NewInt(it.Get())
var exp int
for divModZero(p) {
exp++
}
if 0 < exp {
factors = append(factors, Factor{it.Get(), exp})
}
p.Mul(p, p)
if n.Cmp(p) < 0 {
break
}
}
if one.Cmp(n) < 0 {
factors = append(factors, Factor{MustBigIntToInt64(n), 1})
} else if one.Cmp(n) == 0 && 0 == len(factors) {
return []Factor{{1, 1}}
}
return factors
}