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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
package factors
import "fmt"
type DigitType struct {
regularity uint8
totativeType TotativeType
}
type TotativeType byte
const (
// This number does not have any totative factors
Regular TotativeType = 0xC0
// This number's totative part is divisible by (r - 1)
// - this gives it the simplest possible decimal expansion
// for a non-regular (1 digit repeating) and a simple divisibility
// test (sum digits, like 3 or 9 in decimal)
Omega TotativeType = 0xA0
// This number's totative part is divisible by (r + 1)
// - this makes it slightly more complicated than omega
Alpha TotativeType = 0x80
// This number's totative part is divisible by (r^2 - 1)
// but not (r + 1) or (r - 1)
// - these totatives straddle the line between simple and complex
Pseudoneighbour TotativeType = 0x60
// This number's totative part is not divisible by (r^2 - 1)
// - it will not be nice to work with
Opaque TotativeType = 0x40
// This number is zero, and doesn't have a true totative type.
// (except in radix zero, where zero is considered a factor)
Zero TotativeType = 0x00
)
// Zero and one will always have these types.
var (
zeroType = DigitType{regularity: 0, totativeType: Zero}
oneType = DigitType{regularity: 0, totativeType: Regular}
)
// Above this number, regularity indices will be shown as '+'
// instead of the number; this is to keep the code 2 characters long
const maxDisplayRegularity = 7
// The regularity index of a number in a radix, the smallest power of the
// radix that is divisible by the number's regular part.
func (dt DigitType) Regularity() uint8 { return dt.regularity }
// The type of a number's totative part in a radix
func (dt DigitType) TotativeType() TotativeType { return dt.totativeType }
// String returns a string representation of the digit type
// as a two-character code - the first representing regularity,
// the second totative type
func (dt DigitType) String() string {
var rString string
if dt.regularity > maxDisplayRegularity {
rString = "+"
} else {
rString = fmt.Sprint(dt.regularity)
}
var tString string
switch dt.totativeType {
case Zero:
tString = "0"
case Regular:
tString = "R"
case Omega:
tString = "ω"
case Alpha:
tString = "α"
case Pseudoneighbour:
tString = "N"
case Opaque:
tString = "P"
}
return rString + tString
}
// Splits a digit in a radix into its regular and totative parts
func splitPF(digit, radix PrimeFactorization) (regular, totative uint) {
regular, totative = 1, 1
for p, e := range digit.exponents {
if radix.exponents[p] != 0 {
regular *= uintpow(p, e)
} else {
totative *= uintpow(p, e)
}
}
return regular, totative
}
// Splits a digit in a radix into its regular and totative parts
func Split(digit, radix uint) (regular, totative uint) {
return splitPF(PrimeFactorize(digit), PrimeFactorize(radix))
}
// Calculates the regularity index of a number's regular part
func calcRegularity(regular, radix uint) uint8 {
if regular == 0 && radix == 0 {
return 1
}
regularity, radixPower := uint8(0), uint(1)
for radixPower%regular != 0 {
regularity++
radixPower *= radix
}
return regularity
}
// Calculates the totative type of a number's totative part
func calcTotativeType(totative, radix uint) TotativeType {
switch true {
case totative == 0:
return Zero
case totative == 1:
return Regular
case (radix-1)%totative == 0:
return Omega
case (radix+1)%totative == 0:
return Alpha
case (radix*radix-1)%totative == 0:
return Pseudoneighbour
default:
return Opaque
}
}
// Gets the regularity and totative type of one digit in a radix
// In radix zero, zero is type 1R, one is type 0R, and everything else is 0P.
func GetDigitType(digit, radix uint) DigitType {
radixPF := PrimeFactorize(radix)
digitPF := PrimeFactorize(digit)
regular, totative := splitPF(digitPF, radixPF)
regularity := calcRegularity(regular, radix)
totativeType := calcTotativeType(totative, radix)
return DigitType{regularity, totativeType}
}
// Gets the regularity and totative type of each digit in a radix
func DigitMap(radix uint) []DigitType {
radixPF := PrimeFactorize(radix)
types := make([]DigitType, radix, radix)
if radix > 0 {
types[0] = zeroType
}
if radix > 1 {
types[1] = oneType
}
for d := uint(2); d < radix; d++ {
digitPF := PrimeFactorize(d)
regular, totative := splitPF(digitPF, radixPF)
regularity := calcRegularity(regular, radix)
totativeType := calcTotativeType(totative, radix)
types[d] = DigitType{regularity, totativeType}
}
return types
}
|