diff options
| author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2023-10-09 16:15:48 -0500 |
|---|---|---|
| committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2023-10-09 16:16:29 -0500 |
| commit | c50ece109cdb29ab5d3fa7444040b546da7e360c (patch) | |
| tree | 33fbf5678f2030a85f6c4b4f20ff5fc302516c53 /factors | |
| parent | dbd02c8437ae634f4ece3c2979afeb19a3979f61 (diff) | |
factors: Give all exported members proper godoc
Diffstat (limited to 'factors')
| -rw-r--r-- | factors/digit_map.go | 57 | ||||
| -rw-r--r-- | factors/factorize.go | 2 | ||||
| -rw-r--r-- | factors/mtc.go | 17 | ||||
| -rw-r--r-- | factors/score.go | 86 | ||||
| -rw-r--r-- | factors/totative.go | 4 | ||||
| -rw-r--r-- | factors/type.go | 6 |
6 files changed, 132 insertions, 40 deletions
diff --git a/factors/digit_map.go b/factors/digit_map.go index a16f018..7c56a1e 100644 --- a/factors/digit_map.go +++ b/factors/digit_map.go @@ -2,11 +2,25 @@ package factors import "fmt" +/* +A DigitType represents the number-theoretical type of a digit in a radix. +It is composed of two parts: + - The regularity index, which is the exponent of the smallest power + of the radix that the digit's regular part (as defined by [Split]) + is a factor of. + - The totative type, which is the [TotativeType] of + the radix's totative part (as defined by [Split]). + +The zero value of DigitType is the type 00, +the type that the digit zero has in every nonzero radix. +*/ type DigitType struct { regularity uint8 totativeType TotativeType } +// TotativeType classifies the totative parts (as determined by [Split]) +// of digits in radices. type TotativeType byte const ( @@ -42,16 +56,28 @@ var ( // 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 +// The regularity index of a number in a radix - the smallest power of the // radix that is divisible by the number's regular part. +// +// If this is zero, and the digit isn't, this digit is a totative. func (dt DigitType) Regularity() uint8 { return dt.regularity } -// The type of a number's totative part in a radix +// TotativeType returns the type of a number's totative part in a radix. +// This is one of the possible values of [TotativeType]. 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 +// String returns a string representation of the digit type. +// +// This representation is a two-character code. +// The first character is the type's [DigitType.Regularity], +// or "+" if it is above 7. +// The second character is a character representing the [TotativeType]: +// - [Regular] is 'R' +// - [Omega] is 'ω' +// - [Alpha] is 'α' +// - [Pseudoneighbour] is 'N' +// - [Opaque] is 'P' (to avoid confusing it with [Zero]) +// - [Zero] is '0' func (dt DigitType) String() string { var rString string if dt.regularity > maxDisplayRegularity { @@ -92,7 +118,19 @@ func splitPF(digit, radix PrimeFactorization) (regular, totative uint) { return regular, totative } -// Splits a digit in a radix into its regular and totative parts +/* +Split splits a digit in a radix into its regular and totative parts. +The regular part will be a divisor of some power of the radix. +The totative part will be coprime to the radix, +except if the digit or radix are zero. +The product of the regular and totative parts will be equal to the digit. + +Special cases (follow from PrimeFactorize(0) = 0^1): + + Split(0, x) = 1, 0 + Split(x, 0) = 1, x + Split(0, 0) = 0, 1 +*/ func Split(digit, radix uint) (regular, totative uint) { return splitPF(PrimeFactorize(digit), PrimeFactorize(radix)) } @@ -129,7 +167,8 @@ func calcTotativeType(totative, radix uint) TotativeType { } } -// Gets the regularity and totative type of one digit in a radix +// 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) @@ -140,7 +179,9 @@ func GetDigitType(digit, radix uint) DigitType { return DigitType{regularity, totativeType} } -// Gets the regularity and totative type of each digit in a radix +// DigitMap gets the [DigitType] of every digit in a radix. +// +// DigitMap(0) returns an empty slice. func DigitMap(radix uint) []DigitType { radixPF := PrimeFactorize(radix) types := make([]DigitType, radix, radix) diff --git a/factors/factorize.go b/factors/factorize.go index 9aa43a7..16cd810 100644 --- a/factors/factorize.go +++ b/factors/factorize.go @@ -2,6 +2,8 @@ package factors // Factors returns a number's factors as a slice. // The slice is not guaranteed to be in sorted order. +// +// Because every number is a factor of zero, Factors(0) panics. func Factors(n uint) []uint { if n == 0 { panic("Cannot get factors of 0!") diff --git a/factors/mtc.go b/factors/mtc.go index 024391e..4d40396 100644 --- a/factors/mtc.go +++ b/factors/mtc.go @@ -3,10 +3,21 @@ package factors // MTC returns the multiplication table complexity of a radix n. // This is an estimate of how difficult it is to learn a radix's // multiplication table. -func MTC(n uint32) uint64 { +// +// The MTC is a sum of each digit's row complexity, +// which is the length of the pattern of the product's last digit +// (equal to digit / gcd(digit, radix)). +// Digits 1 and radix - 1 are excluded because they have simpler patterns +// than the other digits. +// +// uint32 is used as the input type and uint64 as the output to prevent +// integer overflow (and because the MTC algorithm is slow). +// +// The MTC of 0 and 1 are both zero. +func MTC(radix uint32) uint64 { mtc := uint64(0) - for i := uint32(2); i <= n-2; i++ { - mtc += uint64(n / gcd(i, n)) + for digit := uint32(2); digit <= radix-2; digit++ { + mtc += uint64(radix / gcd(digit, radix)) } return mtc } diff --git a/factors/score.go b/factors/score.go index 00988c9..b1da963 100644 --- a/factors/score.go +++ b/factors/score.go @@ -5,21 +5,29 @@ import ( "math/big" ) -// Score returns a "factor score" equal to the sum of the reciprocoals -// of the number n's factors. -// Rationale: -// A number's factors are one of the most important things that determines -// how well it functions as a number base. An easy way to determine how -// good these factors are is to simply count them, but that comes with -// the problem that all factors are considered equal when they really aren't -// - divisibility by 2 (which ensures 1/2 is a terminating fraction and -// you can tell whether a number is even or odd by looking at the last digit) -// is more important than divisibility by 23. The most obvious way of -// accounting for this is by giving each factor a score and adding those -// scores to get the overall score. I chose score(f) = 1/f because it is -// the simplest function that captures the intuition that smaller factors -// are more valuable than larger ones. It also gives the score a meaning: -// a factor's score is the probability a random number is divisible by it. +/* +Score returns a "factor score" equal to the sum of the reciprocoals +of the number n's factors. + +Rationale: +A number's factors are one of the most important things that determines +how well it functions as a number radix. An easy way to determine how +good these factors are is to simply count them, but that comes with +the problem that all factors are considered equal when they really aren't +- divisibility by 2 (which ensures 1/2 is a terminating fraction and +you can tell whether a number is even or odd by looking at the last digit) +is more important than divisibility by 23. The most obvious way of +accounting for this is by giving each factor a score and adding those +scores to get the overall score. I chose score(f) = 1/f because it is +the simplest function that captures the intuition that smaller factors +are more valuable than larger ones. It also gives the score a meaning: +a factor's score is the probability a random number is divisible by it. + +Special cases: + + Score(0) = NaN + Score(1) = 1.0 +*/ func Score(n uint) float64 { if n == 0 { return math.NaN() @@ -54,30 +62,54 @@ func bigScore(n uint) float64 { return score64 } -// BasicRank returns a rank describing how well a radix handles the simplest -// fractions (1/2, 1/3, 1/4 and 1/5). Zero and one are not true radices, -// but because this rank otherwise only depends on a radix's remainder -// mod 60, they have the same ranks as 60 and 61 (A+, F~). -// Also known as 2345 Rank. -func BasicRank(n uint) string { +/* +BasicRank returns a rank describing how well a radix handles the simplest +fractions (1/2, 1/3, 1/4, 1/5). It consists of two parts: a letter (A-F) +and a sign (+, -, ~). It is also known as the 2345 Rank. + +The letter determines how well the first three fractions are handled +(specifically, what their decimal expansions look like): + - A means all three terminate with one digit. + - B means 1/2 and 1/3 terminate with one digit, + and 1/4 terminates with two digits. + - C means 1/2 and 1/4 terminate with one digit, + but 1/3 is infinitely repeating (pattern length 1-2 digits). + - D means 1/2 terminates with one digit, + but 1/3 is infinitely repeating (pattern length 1-2 digits), + and 1/4 terminates with two digits. + - E means 1/3 terminates with one digit, + but 1/2 and 1/4 are infinitely repeating + (pattern lengths 1 and 1-2 respectively). + - F means all three are infinitely repeating + (pattern lengths 1, 1-2 and 1-2 respectively). + +The sign determines how well 1/5 is handled: + - A plus means it terminates with one digit. + - A tilde means it repeats with a short (1-2 digit) pattern. + - A minus means it repeats with a long (4-digit) pattern. + +Because the rank only depends on radix % 60, 0 and 1 are given the same +ranks as 60 and 61 (A+, F~). +*/ +func BasicRank(radix uint) string { var firstRank, secondRank string switch uint(0) { - case n % 12: + case radix % 12: firstRank = "A" - case n % 6: + case radix % 6: firstRank = "B" - case n % 4: + case radix % 4: firstRank = "C" - case n % 2: + case radix % 2: firstRank = "D" - case n % 3: + case radix % 3: firstRank = "E" default: firstRank = "F" } - switch n % 5 { + switch radix % 5 { case 0: secondRank = "+" case 1, 4: diff --git a/factors/totative.go b/factors/totative.go index d1947b6..9dde4b0 100644 --- a/factors/totative.go +++ b/factors/totative.go @@ -1,7 +1,7 @@ package factors // Totient calculates the number of numbers between 1 and n inclusive -// that are totatives of n (share no factors with n) +// that are totatives of n (share no factors with n). func Totient(n uint) uint { if n == 0 { return 0 @@ -20,6 +20,8 @@ func Totient(n uint) uint { // TotativeDigits returns a slice containing every number between 1 and r // inclusive that is a totative of r (shares no factors with r). +// +// The returned slice's length is [Totient](r). func TotativeDigits(r uint32) []uint32 { digits := make([]uint32, Totient(uint(r))) totativesFound := 0 diff --git a/factors/type.go b/factors/type.go index 33c48bd..91eb94e 100644 --- a/factors/type.go +++ b/factors/type.go @@ -41,7 +41,10 @@ var superabundantNums = [...]uint64{ 6133685312708553600, 9200527969062830400, 18401055938125660800, } -// A type of number (as determined by its factors) +// A classification of numbers, based on how many factors they have. +// Each type is a subset of the next (except [Practical] and [NotPractical]), +// so a number is only counted as its most exclusive type. +// The zero value of this type is invalid. type NumberType byte const ( @@ -64,6 +67,7 @@ const ( NotPractical NumberType = 0x40 ) +// Type determines the [NumberType] of a number. func Type(n uint) NumberType { if slices.Contains(colossallyAbundantNums[:], uint64(n)) { return ColossallyAbundant |
