diff options
| author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2023-10-09 13:35:04 -0500 |
|---|---|---|
| committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2023-10-09 13:35:04 -0500 |
| commit | eeff1f3c61fad805bb5ce0170e98378c3b706c18 (patch) | |
| tree | 0cffbefc58b6c9196d779abb249c3c82bce4ffc4 | |
| parent | 194004a9f99096ab724758ba39f39c50c71a21ed (diff) | |
Add more tests & fix found bugs
- TotativeDigits was defined incorrectly, previously counted totatives
from 0 to r-1, now counts digits from 1 to r. This ensures that
len(TotativeDigits(r)) = Totient(r).
| -rw-r--r-- | factors/factors_test.go | 80 | ||||
| -rw-r--r-- | factors/score.go | 2 | ||||
| -rw-r--r-- | factors/totative.go | 10 | ||||
| -rw-r--r-- | radix_info.go | 2 |
4 files changed, 70 insertions, 24 deletions
diff --git a/factors/factors_test.go b/factors/factors_test.go index 0952e8e..ab06aba 100644 --- a/factors/factors_test.go +++ b/factors/factors_test.go @@ -29,11 +29,13 @@ var primeFactorCases = map[uint]PrimeFactorization{ 3: PrimeFactorization{map[uint]uint{3: 1}}, 4: PrimeFactorization{map[uint]uint{2: 2}}, 6: PrimeFactorization{map[uint]uint{2: 1, 3: 1}}, + 9: PrimeFactorization{map[uint]uint{3: 2}}, 10: PrimeFactorization{map[uint]uint{2: 1, 5: 1}}, 12: PrimeFactorization{map[uint]uint{2: 2, 3: 1}}, 33: PrimeFactorization{map[uint]uint{3: 1, 11: 1}}, 60: PrimeFactorization{map[uint]uint{2: 2, 3: 1, 5: 1}}, 71: PrimeFactorization{map[uint]uint{71: 1}}, + 1024: PrimeFactorization{map[uint]uint{2: 10}}, 86400: PrimeFactorization{map[uint]uint{2: 7, 3: 3, 5: 2}}, } @@ -49,6 +51,7 @@ var factorCases = map[uint][]uint{ 2: []uint{1, 2}, 4: []uint{1, 2, 4}, 6: []uint{1, 2, 3, 6}, + 9: []uint{1, 3, 9}, 10: []uint{1, 2, 5, 10}, 12: []uint{1, 2, 3, 4, 6, 12}, 13: []uint{1, 13}, @@ -56,6 +59,8 @@ var factorCases = map[uint][]uint{ 16: []uint{1, 2, 4, 8, 16}, 18: []uint{1, 2, 3, 6, 9, 18}, 30: []uint{1, 2, 3, 5, 6, 10, 15, 30}, + 32: []uint{1, 2, 4, 8, 16, 32}, + 33: []uint{1, 3, 11, 33}, 60: []uint{1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}, 71: []uint{1, 71}, } @@ -65,10 +70,10 @@ func TestFactors(t *testing.T) { } var totativeRatioCases = map[uint]float64{ - 1: 1.0, 2: 0.5, 3: 2.0 / 3.0, 4: 0.5, - 6: 1.0 / 3.0, 7: 6.0 / 7.0, 8: 0.5, - 12: 1.0 / 3.0, 14: 3.0 / 7.0, 15: 8.0 / 15.0, - 30: 4.0 / 15.0, 60: 4.0 / 15.0, 120: 4.0 / 15.0, + 1: 1.0, 2: 0.5, 3: 2.0 / 3.0, 4: 0.5, 6: 1.0 / 3.0, 7: 6.0 / 7.0, 8: 0.5, + 10: 0.4, 12: 1.0 / 3.0, 14: 3.0 / 7.0, 15: 8.0 / 15.0, 16: 0.5, 20: 0.4, + 24: 1.0 / 3.0, 30: 4.0 / 15.0, 60: 4.0 / 15.0, 71: 70.0 / 71.0, + 120: 4.0 / 15.0, } func totativeRatio(n uint) float64 { @@ -80,14 +85,46 @@ func TestTotativeRatio(t *testing.T) { } var totientCases = map[uint]uint{ - 0: 0, 1: 1, 2: 1, 3: 2, 4: 2, 6: 2, 7: 6, 8: 4, 12: 4, - 14: 6, 15: 8, 30: 8, 60: 16, 71: 70, 120: 32, + 0: 0, 1: 1, 2: 1, 3: 2, 4: 2, 6: 2, 7: 6, 8: 4, 10: 4, 12: 4, + 14: 6, 15: 8, 16: 8, 20: 8, 24: 8, 30: 8, 60: 16, 71: 70, 120: 32, } func TestTotativeCount(t *testing.T) { tableTest(t, Totient, totientCases, stdEquals, "Totient") } +var totativeDigitCases = map[uint32][]uint32{ + 0: []uint32{}, + 1: []uint32{1}, + 2: []uint32{1}, + 3: []uint32{1, 2}, + 4: []uint32{1, 3}, + 6: []uint32{1, 5}, + 7: []uint32{1, 2, 3, 4, 5, 6}, + 8: []uint32{1, 3, 5, 7}, + 10: []uint32{1, 3, 7, 9}, + 12: []uint32{1, 5, 7, 11}, + 14: []uint32{1, 3, 5, 9, 11, 13}, + 15: []uint32{1, 2, 4, 7, 8, 11, 13, 14}, + 16: []uint32{1, 3, 5, 7, 9, 11, 13, 15}, + 20: []uint32{1, 3, 7, 9, 11, 13, 17, 19}, + 24: []uint32{1, 5, 7, 11, 13, 17, 19, 23}, + 30: []uint32{1, 7, 11, 13, 17, 19, 23, 29}, + 60: []uint32{1, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53, 59}, + 71: []uint32{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}, + 120: []uint32{1, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53, 59, + 61, 67, 71, 73, 77, 79, 83, 89, 91, 97, 101, 103, 107, 109, 113, 119}, +} + +func TestTotativeDigits(t *testing.T) { + tableTest(t, TotativeDigits, totativeDigitCases, slices.Equal, + "TotativeDigits") +} + var factorScoreCases = map[uint]float64{ 1: 1.0, 2: 1.5, @@ -109,13 +146,17 @@ func TestFactorScore(t *testing.T) { } var basicRankCases = map[uint]string{ - 2: "D-", 3: "E-", 4: "C~", 5: "F+", 6: "B~", - 7: "F-", 8: "C-", 9: "E~", 10: "D+", 11: "F~", 12: "A-", - 14: "D~", 15: "E+", 18: "B-", 20: "C+", 24: "A~", 30: "B+", 60: "A+", + // one test per rank, plus three extra (22, 25, 44) to test that + // n%3 = 1 vs n%3 = 2 doesn't matter + 2: "D-", 3: "E-", 4: "C~", 5: "F+", 6: "B~", 7: "F-", 8: "C-", + 9: "E~", 10: "D+", 11: "F~", 12: "A-", 14: "D~", 15: "E+", 18: "B-", + 20: "C+", 22: "D-", 24: "A~", 25: "F+", 30: "B+", 44: "C~", 60: "A+", // test that it only depends on n%60 - 62: "D-", 63: "E-", 64: "C~", 65: "F+", 66: "B~", - 67: "F-", 68: "C-", 69: "E~", 70: "D+", 71: "F~", 72: "A-", - 74: "D~", 75: "E+", 78: "B-", 80: "C+", 84: "A~", 90: "B+", 120: "A+", + 62: "D-", 63: "E-", 64: "C~", 65: "F+", 66: "B~", 67: "F-", 68: "C-", + 69: "E~", 70: "D+", 71: "F~", 72: "A-", 74: "D~", 75: "E+", 78: "B-", + 80: "C+", 82: "D-", 84: "A~", 85: "F+", 90: "B+", 104: "C~", 120: "A+", + // test that it can extend to 0 and 1 as well + 0: "A+", 1: "F~", } func TestBasicRank(t *testing.T) { @@ -124,6 +165,9 @@ func TestBasicRank(t *testing.T) { var gcdCases = map[struct{ a, b uint32 }]uint32{ {0, 0}: 0, {1, 1}: 1, + {0, 1}: 1, {1, 0}: 1, + {0, 12}: 12, {12, 0}: 12, + {1, 12}: 1, {12, 1}: 1, {6, 10}: 2, {10, 6}: 2, {12, 20}: 4, {20, 12}: 4, {20, 55}: 5, {55, 20}: 5, @@ -172,9 +216,10 @@ func TestSAN(t *testing.T) { } var expOrdCases = map[uint]bool{ - 1: true, 2: true, 4: true, 5: false, 6: true, 12: true, 18: false, - 20: false, 30: true, 44: false, 60: true, 70: false, 96: true, - 101: false, 120: true, 144: true, 770: false, 6912: true, 10010: false, + 0: true, 1: true, 2: true, 4: true, 5: false, 6: true, 8: true, 12: true, + 16: true, 18: false, 20: false, 27: false, 30: true, 36: true, 44: false, + 60: true, 70: false, 90: false, 96: true, 101: false, 120: true, 144: true, + 180: true, 770: false, 900: true, 6912: true, 10010: false, } func TestExponentsOrdered(t *testing.T) { @@ -201,8 +246,9 @@ var typeCases = map[uint]NumberType{ 12: ColossallyAbundant, 18: Practical, 20: Practical, 24: Superabundant, 28: Practical, 30: OrderedExponent, 31: NotPractical, 34: NotPractical, 60: ColossallyAbundant, 70: NotPractical, 90: Practical, 100: Practical, - 120: ColossallyAbundant, 144: OrderedExponent, 240: Superabundant, - 360: ColossallyAbundant, 720: Superabundant, 770: NotPractical, + 120: ColossallyAbundant, 144: OrderedExponent, 180: Superabundant, + 240: Superabundant, 360: ColossallyAbundant, 720: Superabundant, + 770: NotPractical, 900: OrderedExponent, 1680: Superabundant, 1729: NotPractical, 6912: OrderedExponent, 10010: NotPractical, 10080: Superabundant, 15120: Superabundant, 25200: Superabundant, 27720: Superabundant, 55440: ColossallyAbundant, diff --git a/factors/score.go b/factors/score.go index c777d11..00988c9 100644 --- a/factors/score.go +++ b/factors/score.go @@ -34,7 +34,7 @@ func Score(n uint) float64 { return float64(factorSum) / float64(n) } -const maxSmall = 1 << 28 - 1 +const maxSmall = 1<<28 - 1 func bigScore(n uint) float64 { factorSum := new(big.Int) diff --git a/factors/totative.go b/factors/totative.go index abbbe89..d1947b6 100644 --- a/factors/totative.go +++ b/factors/totative.go @@ -1,7 +1,7 @@ package factors -// Totient calculates the number of numbers less than n that -// are totatives of n (share no factors with n) +// Totient calculates the number of numbers between 1 and n inclusive +// that are totatives of n (share no factors with n) func Totient(n uint) uint { if n == 0 { return 0 @@ -18,12 +18,12 @@ func Totient(n uint) uint { return num * (n / denom) } -// TotativeDigits returns a slice containing every number less than r -// that is a totative of r (shares no factors with r). +// TotativeDigits returns a slice containing every number between 1 and r +// inclusive that is a totative of r (shares no factors with r). func TotativeDigits(r uint32) []uint32 { digits := make([]uint32, Totient(uint(r))) totativesFound := 0 - for d := uint32(0); d < r; d++ { + for d := uint32(1); d <= r; d++ { if gcd(d, r) == 1 { digits[totativesFound] = d totativesFound++ diff --git a/radix_info.go b/radix_info.go index 866a8f5..c786fb8 100644 --- a/radix_info.go +++ b/radix_info.go @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. - */ +*/ package main |
