package main import ( "aphopkins/radix_info/factors" "fmt" "io" "math" "slices" ) // FactorInfo contains all of the information this program // calculates about a radix. type FactorInfo struct { // The radix this info is about Radix uint // A representation of this radix as a product of prime numbers. // Most of the important info about radices is determined through this. PrimeFactorization factors.PrimeFactorization // The radix's factors, in sorted order. Factors []uint // An estimate of the utility of the radix's factors. Score float64 // The number of digits that are totatives (numbers that share no // factors with the radix - they are the worst kind of digits) Totient uint // The fraction of digits that are totatives (numbers that share no // factors with the radix - they are the worst kind of digits) TotativeRatio float64 // A rank measuring how well the radix works with the most elementary // numbers and ratios BasicRank string // Whether or not this radix is part of any special factor-related classes. // This is not calculated if the radix is too large - in this case // this field will be nil. Type *factors.NumberType // An estimate of the complexity of the radix's multiplication table. // This is not calculated if the radix is too large - in this case // this field will be nil. MTC *uint64 // The radix's natural logarithm. This determines the length of numbers // in this radix - higher Ln means numbers take up fewer digits. // If c = log(a)/log(b), then numbers in radix b will be around // c times longer than numbers in radix a. Ln float64 // Information about each digit's compatibility with the radix. // This determines what kind of decimal expansion the digit's // reciprocoal has and what patterns are in its row of the multiplication // table. DigitMap []factors.DigitType } const ( // The maximum radix that will always be treated as normal // (i.e. radix type and exact MTC will be calculated) maxNormal = 1 << 16 // The max radix that will be treated as normal with -l // above this, MTC can exceed the size of a uint64 maxExtended = 1 << 32 ) func GetFactorInfo(radix uint, fullMap bool, largeCalc bool) *FactorInfo { r_factors := factors.Factors(radix) slices.Sort(r_factors) var r_type_ptr *factors.NumberType var mtc_ptr *uint64 if radix < maxNormal || (largeCalc && radix < maxExtended) { r_type := factors.Type(uint32(radix)) r_type_ptr = &r_type mtc := factors.MTC(uint64(radix)) mtc_ptr = &mtc } else { r_type_ptr = nil mtc_ptr = nil } var digitMap []factors.DigitType if fullMap { digitMap = make([]factors.DigitType, maxSmallRadix) for d := 0; d < maxSmallRadix; d++ { digitMap[d] = factors.GetDigitType(uint(d), radix) } } else if radix <= maxSmallRadix { digitMap = factors.DigitMap(radix) } else { digitMap = []factors.DigitType{} } totativeCount := factors.Totient(radix) totativeRatio := float64(totativeCount) / float64(radix) return &FactorInfo{radix, factors.PrimeFactorize(radix), r_factors, factors.Score(radix), totativeCount, totativeRatio, factors.BasicRank(radix), r_type_ptr, mtc_ptr, math.Log(float64(radix)), digitMap} } func (fi *FactorInfo) WriteTo(w io.Writer) { fmt.Fprintln(w, fi.Radix, "=", fi.PrimeFactorization) fmt.Fprintf(w, "Factors: %v (Score: %.4f)\n", fi.Factors, fi.Score) fmt.Fprintln(w, "2345 Rank:", fi.BasicRank) fmt.Fprintf(w, "Totative Digit Count: %d (%.3f%%)\n", fi.Totient, fi.TotativeRatio*100.0) if fi.Type != nil { writeTypeMessage(w, *fi.Type) } if fi.MTC != nil { fmt.Fprintln(w, "Multiplication Table Complexity:", *fi.MTC) } else { low_mtc_est := float64(fi.Radix) * float64(fi.Totient-2) high_mtc_est := float64(fi.Radix) * float64(fi.Radix-2) fmt.Fprintf(w, "Multiplication Table Complexity is between %.6g and %.6g.\n", low_mtc_est, high_mtc_est) } fmt.Fprintf(w, "Natural Logarithm: %.3f\n", fi.Ln) if len(fi.DigitMap) > 0 { writeDigitMap(w, fi.DigitMap) } } func (fi *FactorInfo) WriteToCompact(w io.Writer) { fmt.Fprintf(w, "%d = %s | σ(n)/n: %.2f | φ(n)/n: %.3f\n", fi.Radix, fi.PrimeFactorization, fi.Score, fi.TotativeRatio) if fi.Type != nil { fmt.Fprintf(w, "%s | ", typeAbbrev(*fi.Type)) } if fi.MTC != nil { fmt.Fprintf(w, "MTC: %d | ", *fi.MTC) } else { low_mtc_est := float32(fi.Radix) * float32(fi.Totient-2) high_mtc_est := float32(fi.Radix) * float32(fi.Radix-2) fmt.Fprintf(w, "%.4g ≤ MTC ≤ %.4g | ", low_mtc_est, high_mtc_est) } fmt.Fprintf(w, "Ln: %.2f", fi.Ln) fmt.Fprintln(w) if len(fi.DigitMap) > 0 { writeDigitMapCompact(w, fi.DigitMap) } } func writeTypeMessage(w io.Writer, t factors.NumberType) { switch t { case factors.ColossallyAbundant: fmt.Fprintln(w, "This radix is colossally abundant!") case factors.Superabundant: fmt.Fprintln(w, "This radix is superabundant.") case factors.OrderedExponent: fmt.Fprintln(w, "This radix has ordered exponents.") case factors.Practical: fmt.Fprintln(w, "This radix is practical.") } } func typeAbbrev(t factors.NumberType) string { switch t { case factors.ColossallyAbundant: return "Colossally Abundant" case factors.Superabundant: return "Superabundant" case factors.OrderedExponent: return "Ordered Exponents" case factors.Practical: return "Practical" case factors.NotPractical: return "Not Practical" default: panic("Should not be possible to get here.") } }