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 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 } func GetFactorInfo(radix uint) *FactorInfo { r_factors := factors.Factors(radix) slices.Sort(r_factors) var r_type_ptr *factors.NumberType var mtc_ptr *uint64 if radix < 1<<32 { 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 radix <= maxSmallRadix { digitMap = factors.DigitMap(radix) } else { digitMap = []factors.DigitType{} } return &FactorInfo{radix, factors.PrimeFactorize(radix), r_factors, factors.Score(radix), factors.TotativeRatio(radix), 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.Fprintf(w, "Totative Ratio: %.3f%%\n", fi.TotativeRatio * 100.0) fmt.Fprintln(w, "2345 Rank:", fi.BasicRank) if fi.Type != nil { writeTypeMessage(w, *fi.Type) } if fi.MTC != nil { fmt.Fprintln(w, "Multiplication Table Complexity:", *fi.MTC) } else { fmt.Fprintf(w, "Multiplication Table Complexity ≤ %.4g\n", float32(fi.Radix)*float32(fi.Radix-2)) } 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 | 2345: %s\n", fi.Radix, fi.PrimeFactorization, fi.Score, fi.TotativeRatio, fi.BasicRank) fmt.Fprintf(w, "Ln: %.2f", fi.Ln) if fi.MTC != nil { fmt.Fprintf(w, " | MTC: %d", *fi.MTC) } if fi.Type != nil { fmt.Fprintf(w, " | %s", typeAbbrev(*fi.Type)) } 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.") } }