summaryrefslogtreecommitdiff
path: root/factors/score.go
diff options
context:
space:
mode:
authorAdrien Hopkins <adrien.p.hopkins@gmail.com>2023-09-19 19:44:35 -0500
committerAdrien Hopkins <adrien.p.hopkins@gmail.com>2023-09-19 19:44:35 -0500
commit3cf61177898fad4e6be85b52083e9c1b508d6568 (patch)
tree8ba1c616a16d15a6b05fec44481a4afca22b977b /factors/score.go
parent165e55184e79553c74b9c9056fd46f1b37a2b5d9 (diff)
factors.Score: Avoid overflow by using math/big
When using really large numbers, factors.Score could overflow, which would cause an incorrect result. Using arbitrary-precision arithmetic fixes this. I only do so above 2^28, since below then factor sums are guaranteed to not overflow, and normal arithmetic is faster.
Diffstat (limited to 'factors/score.go')
-rw-r--r--factors/score.go27
1 files changed, 26 insertions, 1 deletions
diff --git a/factors/score.go b/factors/score.go
index 0759a74..c777d11 100644
--- a/factors/score.go
+++ b/factors/score.go
@@ -1,6 +1,9 @@
package factors
-import "math"
+import (
+ "math"
+ "math/big"
+)
// Score returns a "factor score" equal to the sum of the reciprocoals
// of the number n's factors.
@@ -20,6 +23,8 @@ import "math"
func Score(n uint) float64 {
if n == 0 {
return math.NaN()
+ } else if n > maxSmall {
+ return bigScore(n)
}
factorSum := uint(0)
@@ -29,6 +34,26 @@ func Score(n uint) float64 {
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