package factors import ( "math" "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. func Score(n uint) float64 { if n == 0 { return math.NaN() } else if n > maxSmall { return bigScore(n) } factorSum := uint(0) for _, f := range Factors(n) { factorSum += f } return float64(factorSum) / float64(n) } const maxSmall = 1 << 28 - 1 func bigScore(n uint) float64 { factorSum := new(big.Int) // initialize bigFactor like this to avoid reallocating memory bigFactor := new(big.Int).SetUint64(uint64(n)) for _, f := range Factors(n) { bigFactor.SetUint64(uint64(f)) factorSum.Add(factorSum, bigFactor) } bigN := new(big.Int).SetUint64(uint64(n)) score := new(big.Rat).SetFrac(factorSum, bigN) score64, _ := score.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 { var firstRank, secondRank string switch uint(0) { case n % 12: firstRank = "A" case n % 6: firstRank = "B" case n % 4: firstRank = "C" case n % 2: firstRank = "D" case n % 3: firstRank = "E" default: firstRank = "F" } switch n % 5 { case 0: secondRank = "+" case 1, 4: secondRank = "~" case 2, 3: secondRank = "-" } return firstRank + secondRank }