How to resolve the algorithm Chernick's Carmichael numbers step by step in the Go programming language

Published on 12 May 2024 09:40 PM
#Go

How to resolve the algorithm Chernick's Carmichael numbers step by step in the Go programming language

Table of Contents

Problem Statement

In 1939, Jack Chernick proved that, for n ≥ 3 and m ≥ 1: is a Carmichael number if all the factors are primes and, for n > 4, m is a multiple of 2^(n-4).

For n = 5, the smallest number m that satisfy Chernick's conditions, is m = 380, therefore U(5, 380) is the smallest Chernick's Carmichael number with 5 prime factors. U(5, 380) is a Chernick's Carmichael number because m = 380 is a multiple of 2^(n-4), where n = 5, and the factors { (6380 + 1), (12380 + 1), (18380 + 1), (36380 + 1), (72*380 + 1) } are all prime numbers.

For n ≥ 3, let a(n) be the smallest Chernick's Carmichael number with n prime factors.

Note: it's perfectly acceptable to show the terms in factorized form:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Chernick's Carmichael numbers step by step in the Go programming language

The provided Go (*) code finds and prints the values for the Carmichael numbers, a(n), within a specified range. Carmichael numbers are special numbers that satisfy certain mathematical properties related to Carmichael functions, which are defined as:

  • a(n) = Π(p - 1) mod p^n
  • p is a prime number that divides (n+1)

To efficiently calculate these values, the code uses optimizations and primality tests to determine Carmichael numbers within a given range, then prints the results.

Here's a detailed breakdown of the code:

package main

import (
   "fmt"
   big "github.com/ncw/gmp"
)

This section imports the necessary libraries, including the GMP library (github.com/ncw/gmp), which provides high-precision arithmetic operations.

const (
   min = 3
   max = 10
)

var (
   prod       = new(big.Int)
   fact       = new(big.Int)
   factors    = [max]uint64{}
   bigFactors = [max]*big.Int{}
)

Here, constants and variables are being declared:

  • min and max define the range of Carmichael numbers to be computed.
  • prod and fact are big.Int variables used for intermediate calculations.
  • factors is an array of uint64 values to store prime factors of the Carmichael numbers.
  • bigFactors is an array of *big.Int values to store big.Int representations of the prime factors.
func init() {
   for i := 0; i < max; i++ {
       bigFactors[i] = big.NewInt(0)
   }
}

This initializes the bigFactors array with big.Int values set to zero.

func isPrimePretest(k uint64) bool {
   if k%3 == 0 || k%5 == 0 || k%7 == 0 || k%11 == 0 ||
       k%13 == 0 || k%17 == 0 || k%19 == 0 || k%23 == 0 {
       return k <= 23
   }
   return true
}

The isPrimePretest function performs a quick primality test by checking if the given number k is divisible by a set of small prime numbers. If k is divisible by any of these primes and is not equal to 23, it returns false, indicating that k is not prime. Otherwise, it returns true, indicating that k is likely prime.

func ccFactors(n, m uint64) bool {
   if !isPrimePretest(6*m + 1) {
       return false
   }
   if !isPrimePretest(12*m + 1) {
       return false
   }
   factors[0] = 6*m + 1
   factors[1] = 12*m + 1
   t := 9 * m
   for i := uint64(1); i <= n-2; i++ {
       tt := (t << i) + 1
       if !isPrimePretest(tt) {
           return false
       }
       factors[i+1] = tt
   }

   for i := 0; i < int(n); i++ {
       fact.SetUint64(factors[i])
       if !fact.ProbablyPrime(0) {
           return false
       }
       bigFactors[i].Set(fact)
   }
   return true
}

The ccFactors function takes two uint64 values, n and m, as input and checks whether n meets the criteria to be a Carmichael number. It does this by performing the following steps:

  1. It first applies the isPrimePretest function to quickly check if the required prime factors (6m + 1 and 12m + 1) are likely to be prime. If not, it returns false.
  2. It populates the factors array with the required prime factors and their powers.
  3. It iterates from i = 1 to n-2 and computes the next prime factor, tt, required for the Carmichael function computation, using bit shifts and addition. It again applies the isPrimePretest function to ensure that tt is likely prime.
  4. It stores the found prime factors in the factors array.
  5. It converts the prime factors in the factors array to big.Int values and stores them in the bigFactors array.
  6. It checks if all the converted prime factors are probably prime using the ProbablyPrime method. If any of them are not probably prime, it returns false.
  7. If all checks pass, it returns true, indicating that n satisfies the Carmichael number property.
func prodFactors(n uint64) *big.Int {
   prod.Set(bigFactors[0])
   for i := 1; i < int(n); i++ {
       prod.Mul(prod, bigFactors[i])
   }
   return prod
}

The prodFactors function takes n as input and computes the product of prime factors stored in the bigFactors array. It returns the resulting big.Int value.

func ccNumbers(start, end uint64) {
   for n := start; n <= end; n++ {
       mult := uint64(1)
       if n > 4 {
           mult = 1 << (n - 4)
       }
       if n > 5 {
           mult *= 5
       }
       m := mult
       for {
           if ccFactors(n, m) {
               num := prodFactors(n)
               fmt.Printf("a(%d) = %d\n", n, num)
               fmt.Printf("m(%d) = %d\n", n, m)
               fmt.Println("Factors:", factors[:n], "\n")
               break
           }
           m += mult
       }
   }
}

The ccNumbers function is the main loop that iterates through the range of Carmichael numbers specified by start and end to find and print Carmichael

numbers. It does this by:

  1. Calculating the multiplier mult based on the value of n.
  2. Starting with m equal to mult, it repeatedly calls the ccFactors function, incrementing m by mult each time, until it finds a valid Carmichael number.
  3. Once a valid Carmichael number is found, it prints the value of the Carmichael function a(n), the corresponding m value, and the prime factors used in the calculation.

In summary, this code efficiently computes and prints Carmichael numbers within a specified range by employing optimizations and primality tests to reduce the computational complexity and improve accuracy.

Source code in the go programming language

package main

import (
    "fmt"
    "math/big"
)

var (
    zero = new(big.Int)
    prod = new(big.Int)
    fact = new(big.Int)
)

func ccFactors(n, m uint64) (*big.Int, bool) {
    prod.SetUint64(6*m + 1)
    if !prod.ProbablyPrime(0) {
        return zero, false
    }
    fact.SetUint64(12*m + 1)
    if !fact.ProbablyPrime(0) { // 100% accurate up to 2 ^ 64
        return zero, false
    }
    prod.Mul(prod, fact)
    for i := uint64(1); i <= n-2; i++ {
        fact.SetUint64((1<<i)*9*m + 1)
        if !fact.ProbablyPrime(0) {
            return zero, false
        }
        prod.Mul(prod, fact)
    }
    return prod, true
}

func ccNumbers(start, end uint64) {
    for n := start; n <= end; n++ {
        m := uint64(1)
        if n > 4 {
            m = 1 << (n - 4)
        }
        for {
            num, ok := ccFactors(n, m)
            if ok {
                fmt.Printf("a(%d) = %d\n", n, num)
                break
            }
            if n <= 4 {
                m++
            } else {
                m += 1 << (n - 4)
            }
        }
    }
}

func main() {
    ccNumbers(3, 9)
}


package main

import (
    "fmt"
    big "github.com/ncw/gmp"
)

const (
    min = 3
    max = 10
)

var (
    prod       = new(big.Int)
    fact       = new(big.Int)
    factors    = [max]uint64{}
    bigFactors = [max]*big.Int{}
)

func init() {
    for i := 0; i < max; i++ {
        bigFactors[i] = big.NewInt(0)
    }
}

func isPrimePretest(k uint64) bool {
    if k%3 == 0 || k%5 == 0 || k%7 == 0 || k%11 == 0 ||
        k%13 == 0 || k%17 == 0 || k%19 == 0 || k%23 == 0 {
        return k <= 23
    }
    return true
}

func ccFactors(n, m uint64) bool {
    if !isPrimePretest(6*m + 1) {
        return false
    }
    if !isPrimePretest(12*m + 1) {
        return false
    }
    factors[0] = 6*m + 1
    factors[1] = 12*m + 1
    t := 9 * m
    for i := uint64(1); i <= n-2; i++ {
        tt := (t << i) + 1
        if !isPrimePretest(tt) {
            return false
        }
        factors[i+1] = tt
    }

    for i := 0; i < int(n); i++ {
        fact.SetUint64(factors[i])
        if !fact.ProbablyPrime(0) {
            return false
        }
        bigFactors[i].Set(fact)
    }
    return true
}

func prodFactors(n uint64) *big.Int {
    prod.Set(bigFactors[0])
    for i := 1; i < int(n); i++ {
        prod.Mul(prod, bigFactors[i])
    }
    return prod
}

func ccNumbers(start, end uint64) {
    for n := start; n <= end; n++ {
        mult := uint64(1)
        if n > 4 {
            mult = 1 << (n - 4)
        }
        if n > 5 {
            mult *= 5
        }
        m := mult
        for {
            if ccFactors(n, m) {
                num := prodFactors(n)
                fmt.Printf("a(%d) = %d\n", n, num)
                fmt.Printf("m(%d) = %d\n", n, m)
                fmt.Println("Factors:", factors[:n], "\n")
                break
            }
            m += mult
        }
    }
}

func main() {
    ccNumbers(min, max)
}


  

You may also check:How to resolve the algorithm Conditional structures step by step in the МК-61/52 programming language
You may also check:How to resolve the algorithm Prime decomposition step by step in the Seed7 programming language
You may also check:How to resolve the algorithm Repeat step by step in the Rust programming language
You may also check:How to resolve the algorithm Anonymous recursion step by step in the Racket programming language
You may also check:How to resolve the algorithm Greedy algorithm for Egyptian fractions step by step in the RPL programming language