From ac766f4f6ab9db683e29b093bbc48cfe3b27b2b7 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 22 Sep 2025 15:56:30 -0500 Subject: Show regular complexity of prime factors This metric shows how many combinations you'll need to memorize prime powers, and how big the numbers are in complementary multiplication. The YouTube video "the best way to count" inspired me to think I need a metric to handle both size and factors, but the specific metric is entirely original (or at least independently discovered). --- factors/table_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'factors/table_test.go') diff --git a/factors/table_test.go b/factors/table_test.go index c7eeb24..1ff795c 100644 --- a/factors/table_test.go +++ b/factors/table_test.go @@ -18,6 +18,7 @@ package factors import ( "fmt" + "math" "testing" ) @@ -402,6 +403,30 @@ func TestSplit(t *testing.T) { tableTest(t, splitTest, splitCases, stdEquals[uintPair], "Split") } +var primeRegularComplexityCases = map[uint]map[uint]float64{ + 2: {2: 1}, + 3: {3: 1}, + 4: {2: 1}, + 6: {2: 3, 3: 2}, + 10: {2: 5, 5: 2}, + 12: {2: math.Sqrt(3), 3: 4}, + 20: {2: math.Sqrt(5), 5: 4}, + 24: {2: math.Cbrt(3), 3: 8}, + 36: {2: 3, 3: 2}, + 40: {2: math.Cbrt(5), 5: 8}, + 60: {2: math.Sqrt(15), 3: 20, 5: 12}, + 120: {2: math.Cbrt(15), 3: 40, 5: 24}, + 360: {2: math.Cbrt(45), 3: math.Sqrt(40), 5: 72}, +} + +func TestPrimeRegularComplexity(t *testing.T) { + // Use approxEquals instead of == due to differences between + // math.Sqrt/math.Cbrt and math.Pow. + // The different digits are never shown to the user, so no big deal. + tableTest(t, PrimeRegularComplexities, primeRegularComplexityCases, + mapApproxEquals[uint], "PrimeRegularComplexities") +} + // to be used as the equal paramater for tableTest func stdEquals[T comparable](a, b T) bool { return a == b } @@ -421,6 +446,26 @@ func mapEquals[K, V comparable](a, b map[K]V) bool { return true } +func approxEquals(a, b, epsilon float64) bool { + return math.Abs(a-b) <= epsilon*math.Max(math.Abs(a), math.Abs(b)) +} + +func mapApproxEquals[K comparable](a, b map[K]float64) bool { + for k, av := range a { + bv, ok := b[k] + if !ok || !approxEquals(av, bv, 1e-15) { + return false + } + } + for k, bv := range b { + av, ok := a[k] + if !ok || !approxEquals(av, bv, 1e-15) { + return false + } + } + return true +} + func setEquals[E comparable](a, b []E) bool { // use maps to simulate sets // aSet[a] == true means set contains a, false means not -- cgit v1.2.3