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 }