/* This script is part of radix_info. Copyright (C) 2023 Adrien Hopkins This program is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package factors import ( "fmt" "math/rand" "testing" ) // TestFactorsDivisible ensures that every number returned by // Factors is actually a factor of the argument. func TestFactorsDivisible(t *testing.T) { for r := uint(1); r < (1 << 16); r++ { t.Run(fmt.Sprintf("%d", r), func(t *testing.T) { testFactorsDivisibleOnce(t, r) }) } } // One execution of TestFactorsDivisible func testFactorsDivisibleOnce(t *testing.T, r uint) { t.Parallel() factors := Factors(r) for _, factor := range factors { if r%factor != 0 { t.Errorf("%d reported as factor of %d, but not divisible", factor, r) } } } // TestTotatives ensures that every number returned by // TotativeDigits is actually a totative of the argument. // It also tests that len(TotativeDigits(r)) = Totient(r). func TestTotatives(t *testing.T) { for r := uint32(0); r < (1 << 12); r++ { t.Run(fmt.Sprintf("%d", r), func(t *testing.T) { testTotativesOnce(t, r) }) } } // TestTotativesRandom is like TestTotatives, // except it randomly chooses radices. func TestTotativesRandom(t *testing.T) { for testRun := 0; testRun < 144; testRun++ { r := uint32(rand.Int31n(1 << 16)) t.Run(fmt.Sprintf("%d", r), func(t *testing.T) { testTotativesOnce(t, r) }) } } // One execution of TestTotatives func testTotativesOnce(t *testing.T, r uint32) { t.Parallel() totatives := TotativeDigits(r) for _, totative := range totatives { if gcd(totative, r) != 1 { t.Errorf("%d reported as totative of %d, but gcd(%d, %d) = %d", totative, r, totative, r, gcd(totative, r)) } } totient := Totient(uint(r)) if uint(len(totatives)) != totient { t.Errorf( "len(TotativeDigits(%d)) = %d, Totient(%d) = %d, should be equal", r, len(totatives), r, totient) } } // TestSplitProperties tests Split(digit, radix) to ensure // totative is a totative and regular * totative = digit. func TestSplitProperties(t *testing.T) { for radix := uint(1); radix < 1<<7; radix++ { for digit := uint(1); digit < 1<<8; digit++ { t.Run(fmt.Sprintf("radix=%d,digit=%d", radix, digit), func(t *testing.T) { testSplitOnce(t, digit, radix) }) } } } // TestSplitRandom is like TestSplitProperties, // but with randomly chosen values. func TestSplitRandom(t *testing.T) { for i := 0; i < 1728; i++ { radix := uint(rand.Int31n((1<<15)-1)) + 1 digit := uint(rand.Int31n((1<<16)-1)) + 1 t.Run(fmt.Sprintf("radix=%d,digit=%d", radix, digit), func(t *testing.T) { testSplitOnce(t, digit, radix) }) } } // One execution of TestSplitProperties func testSplitOnce(t *testing.T, digit, radix uint) { t.Parallel() regular, totative := Split(digit, radix) if gcd(uint32(totative), uint32(radix)) != 1 { t.Errorf("Split(%d, %d) = %d, %d; %d not coprime to %d.", digit, radix, regular, totative, totative, radix) } if regular*totative != digit { t.Errorf("Split(%d, %d) = %d, %d; %d * %d ≠ %d.", digit, radix, regular, totative, regular, totative, digit) } }