summaryrefslogtreecommitdiff
path: root/factors/prime_factorization.go
blob: f91a2cf78a41640d0296077047d76fcd11319769 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package factors

import (
	"fmt"
	"slices"
	"strings"
)

// PrimeFactorization represents how a number can be represented as a
// product of prime numbers.  This is surprisingly useful for learning
// about number radices.
type PrimeFactorization struct {
	exponents map[uint]uint
}

// PrimeFactorize creates a PrimeFactorization by factorizing a number.
func PrimeFactorize(n uint) PrimeFactorization {
	if n == 0 {
		return PrimeFactorization{map[uint]uint{0: 1}}
	}

	unfactored := n // number with all found factors removed (divided)
	exponents := make(map[uint]uint)

	// try each factor starting at 2
	// if unfactored is divisible divide out until it isn't
	for f := uint(2); f*f <= unfactored; {
		if unfactored%f == 0 {
			unfactored /= f
			exponents[f] += 1
		} else {
			f += 1
		}
	}

	// by this point, unfactored is guaranteed to be 1 or prime
	if unfactored > 1 {
		exponents[unfactored] += 1
	}
	return PrimeFactorization{exponents}
}

// Exponent returns the exponent for the prime p.
func (factors PrimeFactorization) Exponent(p uint) uint {
	return factors.exponents[p]
}

// ExponentMap returns a map mapping primes to their exponents.
func (factors PrimeFactorization) ExponentMap() map[uint]uint {
	exponentMap := make(map[uint]uint, len(factors.exponents))
	for p, e := range factors.exponents {
		exponentMap[p] = e
	}
	return exponentMap
}

// Primes returns a slice containing all of the primes with nonzero exponents
func (factors PrimeFactorization) Primes() []uint {
	primes := make([]uint, 0, len(factors.exponents))
	for p := range factors.exponents {
		if factors.exponents[p] > 0 {
			primes = append(primes, p)
		}
	}
	return primes
}

// Size returns how many primes in this factorization have nonzero exponents.
func (factors PrimeFactorization) Size() int {
	return len(factors.exponents)
}

// String returns a string representation of the prime factorization,
// which looks like "2^2 × 3".
func (factors PrimeFactorization) String() string {
	parts := make([]string, 0, factors.Size())
	primes := make([]int, 0, factors.Size())
	for p := range factors.exponents {
		primes = append(primes, int(p))
	}
	slices.Sort(primes)

	for _, p := range primes {
		if factors.Exponent(uint(p)) == 1 {
			parts = append(parts, fmt.Sprintf("%d", p))
		} else {
			parts = append(parts, fmt.Sprintf("%d^%d", p,
				factors.Exponent(uint(p))))
		}
	}
	return strings.Join(parts, " × ")
}