summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrien Hopkins <adrien.p.hopkins@gmail.com>2023-09-13 19:38:39 -0500
committerAdrien Hopkins <adrien.p.hopkins@gmail.com>2023-09-13 19:38:39 -0500
commitf657d4257e6b39a3899a2ebef8f30f99ebfb313f (patch)
tree16c117ba1ce8c10fd95230fb372c439c1ec6c613
parent345f6bae7b005cdd386833aa496aa71ca11c7b97 (diff)
factors: Remove most panics
Panics are not the best way of handling errors in Go. I've replaced panics with default values whenever a sensible one exists. Factors(0) does not have a sensible default value (as every number is a factor of zero), so it still panics.
-rw-r--r--factors/digit_map.go20
-rw-r--r--factors/factors_test.go30
-rw-r--r--factors/score.go12
3 files changed, 46 insertions, 16 deletions
diff --git a/factors/digit_map.go b/factors/digit_map.go
index 83606e9..a16f018 100644
--- a/factors/digit_map.go
+++ b/factors/digit_map.go
@@ -28,6 +28,7 @@ const (
// - it will not be nice to work with
Opaque TotativeType = 0x40
// This number is zero, and doesn't have a true totative type.
+ // (except in radix zero, where zero is considered a factor)
Zero TotativeType = 0x00
)
@@ -98,6 +99,10 @@ func Split(digit, radix uint) (regular, totative uint) {
// Calculates the regularity index of a number's regular part
func calcRegularity(regular, radix uint) uint8 {
+ if regular == 0 && radix == 0 {
+ return 1
+ }
+
regularity, radixPower := uint8(0), uint(1)
for radixPower%regular != 0 {
regularity++
@@ -125,10 +130,8 @@ func calcTotativeType(totative, radix uint) TotativeType {
}
// 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 {
- if radix < 2 {
- panic("Radices cannot be less than 2!")
- }
radixPF := PrimeFactorize(radix)
digitPF := PrimeFactorize(digit)
regular, totative := splitPF(digitPF, radixPF)
@@ -139,13 +142,14 @@ func GetDigitType(digit, radix uint) DigitType {
// Gets the regularity and totative type of each digit in a radix
func DigitMap(radix uint) []DigitType {
- if radix < 2 {
- panic("Radices cannot be less than 2!")
- }
radixPF := PrimeFactorize(radix)
types := make([]DigitType, radix, radix)
- types[0] = zeroType
- types[1] = oneType
+ if radix > 0 {
+ types[0] = zeroType
+ }
+ if radix > 1 {
+ types[1] = oneType
+ }
for d := uint(2); d < radix; d++ {
digitPF := PrimeFactorize(d)
regular, totative := splitPF(digitPF, radixPF)
diff --git a/factors/factors_test.go b/factors/factors_test.go
index dec651c..a18d30b 100644
--- a/factors/factors_test.go
+++ b/factors/factors_test.go
@@ -68,10 +68,6 @@ var totativeRatioCases = map[uint]float64{
}
func totativeRatio(n uint) float64 {
- if n == 0 {
- panic("0 has no totative ratio!")
- }
-
return float64(Totient(n)) / float64(n)
}
@@ -214,6 +210,8 @@ var (
pt = DigitType{0, Opaque} // 0P - opaque totatives
)
var digitMapCases = map[uint][]DigitType{
+ 0: []DigitType{},
+ 1: []DigitType{zt},
2: []DigitType{zt, ot},
3: []DigitType{zt, ot, wt},
4: []DigitType{zt, ot, ft, wt},
@@ -263,14 +261,38 @@ func TestGetDigitType(t *testing.T) {
}
}
+// A few test cases related to radix zero
+func TestGetDigitTypeMisc(t *testing.T) {
+ t.Run("GetDigitType(0, 0)", func(t *testing.T) {
+ if GetDigitType(0, 0) != ft {
+ t.Errorf("GetDigitType(0, 0) = %s, expected 1R", GetDigitType(0, 0))
+ }
+ })
+ t.Run("GetDigitType(1, 0)", func(t *testing.T) {
+ if GetDigitType(1, 0) != ot {
+ t.Errorf("GetDigitType(1, 0) = %s, expected 0R", GetDigitType(1, 0))
+ }
+ })
+ t.Run("GetDigitType(2, 0)", func(t *testing.T) {
+ if GetDigitType(2, 0) != pt {
+ t.Errorf("GetDigitType(2, 0) = %s, expected 0P", GetDigitType(2, 0))
+ }
+ })
+}
+
var splitCases = map[uintPair]uintPair{
// digit, radix, regular part, totative part
uintPair{0, 0}: uintPair{0, 1},
+ uintPair{0, 1}: uintPair{1, 0},
uintPair{0, 2}: uintPair{1, 0},
uintPair{0, 12}: uintPair{1, 0},
uintPair{1, 0}: uintPair{1, 1},
uintPair{20, 0}: uintPair{1, 20},
uintPair{360, 0}: uintPair{1, 360},
+ uintPair{1, 1}: uintPair{1, 1},
+ uintPair{12, 1}: uintPair{1, 12},
+ uintPair{87, 1}: uintPair{1, 87},
+ uintPair{120, 1}: uintPair{1, 120},
uintPair{1, 2}: uintPair{1, 1},
uintPair{1, 3}: uintPair{1, 1},
uintPair{1, 7}: uintPair{1, 1},
diff --git a/factors/score.go b/factors/score.go
index b47aac4..9288e8f 100644
--- a/factors/score.go
+++ b/factors/score.go
@@ -1,5 +1,7 @@
package factors
+import "math"
+
// Score returns a "factor score" equal to the sum of the reciprocoals
// of the number n's factors.
// Rationale:
@@ -17,7 +19,7 @@ package factors
// a factor's score is the probability a random number is divisible by it.
func Score(n uint) float64 {
if n == 0 {
- panic("Cannot get factor score of 0.")
+ return math.NaN()
}
factorSum := uint(0)
@@ -27,9 +29,11 @@ func Score(n uint) float64 {
return float64(factorSum) / float64(n)
}
-// BasicRank returns a rank describing how well a base handles the simplest
-// fractions (1/2, 1/3, 1/4 and 1/5)
-// also known as 2345 Rank
+// 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
if n%2 == 0 {