How to resolve the algorithm Fermat numbers step by step in the Java programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Fermat numbers step by step in the Java programming language

Table of Contents

Problem Statement

In mathematics, a Fermat number, named after Pierre de Fermat who first studied them, is a positive integer of the form Fn = 22n + 1 where n is a non-negative integer. Despite the simplicity of generating Fermat numbers, they have some powerful mathematical properties and are extensively used in cryptography & pseudo-random number generation, and are often linked to other number theoric fields. As of this writing, (mid 2019), there are only five known prime Fermat numbers, the first five (F0 through F4). Only the first twelve Fermat numbers have been completely factored, though many have been partially factored.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Fermat numbers step by step in the Java programming language

The provided Java code focuses on exploring Fermat numbers and their prime factorization.

Fermat numbers are defined as F[n] = 2^(2^n) + 1. The code calculates the first 10 Fermat numbers and then factorizes the first 12 of them.

  1. Calculating Fermat Numbers:

    • The fermat method computes the Fermat number for a given index n by raising 2 to the power of 2 ^ n and adding 1.
  2. Factorizing Fermat Numbers:

    • The getFactors method finds the prime factors of a given Fermat number n. It uses a combination of trial division and Pollard's rho algorithm.
    • Trial division checks if n is prime (probable prime with 100 iterations) or if it starts with a known composite pattern (stored in the COMPOSITE map). If not, it applies Pollard's rho algorithm to find a factor factor.
    • factor is added to the list of factors, and n is divided by factor to continue the factorization process until n becomes prime.
  3. Pollard's Rho Algorithm:

    • The pollardRhoFast method implements a variant of Pollard's rho algorithm, an integer factorization method. It iteratively calculates x and y values based on the number n.
    • By comparing the difference between x and y, it attempts to find a non-trivial factor of n.
    • The algorithm is optimized using a speed-up technique that involves 100 iterations and one GCD calculation, reducing the factorization time.
  4. Printing the Results:

    • The program displays the first 10 Fermat numbers and the factorization of the first 12 Fermat numbers using the getString method, which converts the list of factors into a string representation.

The code provides a detailed demonstration of Fermat numbers, their factorization, and the use of Pollard's rho algorithm for integer factorization.

Source code in the java programming language

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class FermatNumbers {

    public static void main(String[] args) {
        System.out.println("First 10 Fermat numbers:");
        for ( int i = 0 ; i < 10 ; i++ ) {
            System.out.printf("F[%d] = %s\n", i, fermat(i));
        }
        System.out.printf("%nFirst 12 Fermat numbers factored:%n");
        for ( int i = 0 ; i < 13 ; i++ ) {
            System.out.printf("F[%d] = %s\n", i, getString(getFactors(i, fermat(i))));
        }
    }
    
    private static String getString(List<BigInteger> factors) {
        if ( factors.size() == 1 ) {
            return factors.get(0) + " (PRIME)";
        }
        return factors.stream().map(v -> v.toString()).map(v -> v.startsWith("-") ? "(C" + v.replace("-", "") + ")" : v).collect(Collectors.joining(" * "));
    }

    private static Map<Integer, String> COMPOSITE = new HashMap<>();
    static {
        COMPOSITE.put(9, "5529");
        COMPOSITE.put(10, "6078");
        COMPOSITE.put(11, "1037");
        COMPOSITE.put(12, "5488");
        COMPOSITE.put(13, "2884");
    }

    private static List<BigInteger> getFactors(int fermatIndex, BigInteger n) {
        List<BigInteger> factors = new ArrayList<>();
        BigInteger factor = BigInteger.ONE;
        while ( true ) {
            if ( n.isProbablePrime(100) ) {
                factors.add(n);
                break;
            }
            else {
                if ( COMPOSITE.containsKey(fermatIndex) ) {
                    String stop = COMPOSITE.get(fermatIndex);
                    if ( n.toString().startsWith(stop) ) {
                        factors.add(new BigInteger("-" + n.toString().length()));
                        break;
                    }
                }
                factor = pollardRhoFast(n);
                if ( factor.compareTo(BigInteger.ZERO) == 0 ) {
                    factors.add(n);
                    break;
                }
                else {
                    factors.add(factor);
                    n = n.divide(factor);
                }
            }
        }
        return factors;
    }
    
    private static final BigInteger TWO = BigInteger.valueOf(2);
    
    private static BigInteger fermat(int n) {
        return TWO.pow((int)Math.pow(2, n)).add(BigInteger.ONE);
    }
        
    //  See:  https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
    @SuppressWarnings("unused")
    private static BigInteger pollardRho(BigInteger n) {
        BigInteger x = BigInteger.valueOf(2);
        BigInteger y = BigInteger.valueOf(2);
        BigInteger d = BigInteger.ONE;
        while ( d.compareTo(BigInteger.ONE) == 0 ) {
            x = pollardRhoG(x, n);
            y = pollardRhoG(pollardRhoG(y, n), n);
            d = x.subtract(y).abs().gcd(n);
        }
        if ( d.compareTo(n) == 0 ) {
            return BigInteger.ZERO;
        }
        return d;
    }
    
    //  Includes Speed Up of 100 multiples and 1 GCD, instead of 100 multiples and 100 GCDs.
    //  See Variants section of Wikipedia article.
    //  Testing F[8] = 1238926361552897 * Prime 
    //    This variant = 32 sec.
    //    Standard algorithm = 107 sec.
    private static BigInteger pollardRhoFast(BigInteger n) {
        long start = System.currentTimeMillis();
        BigInteger x = BigInteger.valueOf(2);
        BigInteger y = BigInteger.valueOf(2);
        BigInteger d = BigInteger.ONE;
        int count = 0;
        BigInteger z = BigInteger.ONE;
        while ( true ) {
            x = pollardRhoG(x, n);
            y = pollardRhoG(pollardRhoG(y, n), n);
            d = x.subtract(y).abs();
            z = z.multiply(d).mod(n);
            count++;
            if ( count == 100 ) {
                d = z.gcd(n);
                if ( d.compareTo(BigInteger.ONE) != 0 ) {
                    break;
                }
                z = BigInteger.ONE;
                count = 0;
            }
        }
        long end = System.currentTimeMillis();
        System.out.printf("    Pollard rho try factor %s elapsed time = %d ms (factor = %s).%n", n, (end-start), d);
        if ( d.compareTo(n) == 0 ) {
            return BigInteger.ZERO;
        }
        return d;
    }

    private static BigInteger pollardRhoG(BigInteger x, BigInteger n) {
        return x.multiply(x).add(BigInteger.ONE).mod(n);
    }

}


  

You may also check:How to resolve the algorithm Stirling numbers of the second kind step by step in the Perl programming language
You may also check:How to resolve the algorithm Eban numbers step by step in the Perl programming language
You may also check:How to resolve the algorithm Literals/String step by step in the Nim programming language
You may also check:How to resolve the algorithm Function prototype step by step in the Quackery programming language
You may also check:How to resolve the algorithm Variables step by step in the F# programming language