//JavaClasses/src/main/java/mattrixwv/NumberAlgorithms.java //Matthew Ellison // Created: 07-03-21 //Modified: 06-25-22 //This class contains algorithms for numbers that I've found it useful to keep around /* Copyright (C) 2022 Matthew Ellison This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ package com.mattrixwv; import java.math.BigInteger; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import com.mattrixwv.exceptions.InvalidResult; public class NumberAlgorithms{ private NumberAlgorithms(){} public static final String FACTORIAL_NEGATIVE_MESSAGE = "n! cannot be negative"; //This function returns a list with all the prime numbers <= goalNumber public static List getPrimes(int goalNumber){ return ArrayAlgorithms.longToInt(getPrimes((long) goalNumber)); } public static List getPrimes(long goalNumber){ ArrayList primes = new ArrayList<>(); //Holds the prime numbers boolean foundFactor = false; //A flag for whether a factor of the current number has been found //If the numebr is 0 or negative return an empty list if(goalNumber <= 1){ return primes; } //Otherwise the number is at least 2, so 2 should be added to the list else{ primes.add(2L); } //We cna now start at 3 and skipp all even numbers, because they cannot be prime for(long possiblePrime = 3L;possiblePrime <= goalNumber;possiblePrime += 2L){ //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor Double topPossibleFactor = Math.ceil(Math.sqrt(possiblePrime)); //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this for(int primesCnt = 0;(primesCnt < primes.size()) && (primes.get(primesCnt) <= topPossibleFactor.intValue());++primesCnt){ if((possiblePrime % primes.get(primesCnt)) == 0){ foundFactor = true; break; } } //If you didn't find a factor then the current number must be prime if(!foundFactor){ primes.add(possiblePrime); } else{ foundFactor = false; } } //Sort the list before returning it Collections.sort(primes); return primes; } public static List getPrimes(BigInteger goalNumber){ ArrayList primes = new ArrayList<>(); //Holds the prime numbers boolean foundFactor = false; //A flag for whether a factor of the current number has been found //If the number is 1, 0 or negative return an empty list if(goalNumber.compareTo(BigInteger.valueOf(1)) <= 0){ return primes; } //Otherwise the number is at least 2, so 2 should be added to the list else{ primes.add(BigInteger.valueOf(2)); } //We can now start at 3 and skip all even numbers, because they cannot be prime for(BigInteger possiblePrime = BigInteger.valueOf(3);possiblePrime.compareTo(goalNumber) <= 0;possiblePrime = possiblePrime.add(BigInteger.valueOf(2))){ //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor BigInteger topPossibleFactor = possiblePrime.sqrt().add(BigInteger.valueOf(1)); //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this for(int primesCnt = 0;(primesCnt < primes.size()) && (primes.get(primesCnt).compareTo(topPossibleFactor) <= 0);++primesCnt){ if((possiblePrime.mod(primes.get(primesCnt))) == BigInteger.valueOf(0)){ foundFactor = true; break; } } //If you didn't find a factor then the current number must be prime if(!foundFactor){ primes.add(possiblePrime); } else{ foundFactor = false; } } //Sort the list before returning it Collections.sort(primes); return primes; } //This function gets a certain number of primes public static List getNumPrimes(int numberOfPrimes){ return ArrayAlgorithms.longToInt(getNumPrimes((long)numberOfPrimes)); } public static List getNumPrimes(long numberOfPrimes){ ArrayList primes = new ArrayList<>(); //Holds the prime numbers boolean foundFactor = false; //A flag for whether a factor of the current number has been found //If the number is 0 or negative return an empty list if(numberOfPrimes < 1){ return primes; } //Otherwise the number is at least 2, so 2 should be added to the list else{ primes.add(2L); } //We can now start at 3 and skip all even numbers, because they cannot be prime for(long possiblePrime = 3L;primes.size() < numberOfPrimes;possiblePrime += 2L){ //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor Double topPossibleFactor = Math.ceil(Math.sqrt(possiblePrime)); //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this for(int primesCnt = 0;(primesCnt < primes.size()) && (primes.get(primesCnt) <= topPossibleFactor.intValue());++primesCnt){ if((possiblePrime % primes.get(primesCnt)) == 0){ foundFactor = true; break; } } //If you didn't find a factor then the current number must be prime if(!foundFactor){ primes.add(possiblePrime); } else{ foundFactor = false; } } //Sort the list before returning it Collections.sort(primes); return primes; } public static List getNumPrimes(BigInteger numberOfPrimes){ ArrayList primes = new ArrayList<>(); //Holds the prime numbers boolean foundFactor = false; //A flag for whether a factor of the current number has been found //If the number is 0 or negative return an empty list if(numberOfPrimes.compareTo(BigInteger.valueOf(1)) < 0){ return primes; } //Otherwise the number is at least 2, so 2 should be added to the list else{ primes.add(BigInteger.valueOf(2)); } //We can now start at 3 and skip all even numbers, because they cannot be prime for(BigInteger possiblePrime = BigInteger.valueOf(3);numberOfPrimes.compareTo((BigInteger.valueOf(primes.size()))) > 0;possiblePrime = possiblePrime.add(BigInteger.valueOf(2))){ //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor BigInteger topPossibleFactor = possiblePrime.sqrt().add(BigInteger.valueOf(1)); //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this for(int primesCnt = 0;(primesCnt < primes.size()) && (primes.get(primesCnt).compareTo(topPossibleFactor) <= 0);++primesCnt){ if((possiblePrime.mod(primes.get(primesCnt))) == BigInteger.valueOf(0)){ foundFactor = true; break; } } //If you didn't find a factor then the current number must be prime if(!foundFactor){ primes.add(possiblePrime); } else{ foundFactor = false; } } //Sort the list before returning it Collections.sort(primes); return primes; } //This function return true if the value passed to it is prime public static boolean isPrime(long possiblePrime){ if(possiblePrime <= 3){ return possiblePrime > 1; } else if(((possiblePrime % 2) == 0) || ((possiblePrime % 3) == 0)){ return false; } for(long cnt = 5;(cnt * cnt) <= possiblePrime;cnt += 6){ if(((possiblePrime % cnt) == 0) || ((possiblePrime % (cnt + 2)) == 0)){ return false; } } return true; } public static boolean isPrime(BigInteger possiblePrime){ if(possiblePrime.compareTo(BigInteger.valueOf(3)) <= 0){ return possiblePrime.compareTo(BigInteger.ONE) > 0; } else if(possiblePrime.mod(BigInteger.TWO).equals(BigInteger.ZERO) || possiblePrime.mod(BigInteger.valueOf(3)).equals(BigInteger.ZERO)){ return false; } for(BigInteger cnt = BigInteger.valueOf(5);(cnt.multiply(cnt)).compareTo(possiblePrime) <= 0;cnt = cnt.add(BigInteger.valueOf(6))){ if(possiblePrime.mod(cnt).equals(BigInteger.ZERO) || possiblePrime.mod(cnt.add(BigInteger.TWO)).equals(BigInteger.ZERO)){ return false; } } return true; } //This function returns all factors of goalNumber public static List getFactors(int goalNumber) throws InvalidResult{ return ArrayAlgorithms.longToInt(getFactors((long)goalNumber)); } public static List getFactors(long goalNumber) throws InvalidResult{ //You need to get all the primes that could be factors of this number so you can test them Double topPossiblePrime = Math.ceil(Math.sqrt(goalNumber)); List primes = getPrimes(topPossiblePrime.longValue()); ArrayList factors = new ArrayList<>(); //You need to step through each prime and see if it is a factor in the number for(int cnt = 0;cnt < primes.size();){ //If the prime is a factor you need to add it to the factor list if((goalNumber % primes.get(cnt)) == 0){ factors.add(primes.get(cnt)); goalNumber /= primes.get(cnt); } //Otherwise advance the location in primes you are looking at //By not advancing if the prime is a factor you allow for multiple of the same prime number as a factor else{ ++cnt; } } //If you didn't get any factors the number itself must be a prime if(factors.isEmpty()){ factors.add(goalNumber); goalNumber /= goalNumber; } //If for some reason the goalNumber is not 1 throw an error if(goalNumber != 1){ if(isPrime(goalNumber)){ factors.add(goalNumber); } else{ throw new InvalidResult("The factor was not 1: " + goalNumber); } } //Return the list of factors return factors; } public static List getFactors(BigInteger goalNumber) throws InvalidResult{ //You need to get all the primes that could be factors of this number so you can test them BigInteger topPossiblePrime = goalNumber.divide(BigInteger.TWO); List primes = getPrimes(topPossiblePrime); ArrayList factors = new ArrayList<>(); //You need to step through each prime and see if it is a factor in the number for(int cnt = 0;cnt < primes.size();){ //If the prime is a factor you need to add it to the factor list if((goalNumber.mod(primes.get(cnt))).compareTo(BigInteger.valueOf(0)) == 0){ factors.add(primes.get(cnt)); goalNumber = goalNumber.divide(primes.get(cnt)); } //Otherwise advance the location in primes you are looking at //By not advancing if the prime is a factor you allow for multiple of the same prime number as a factor else{ ++cnt; } } //If you didn't get any factors the number itself must be a prime if(factors.isEmpty()){ factors.add(goalNumber); goalNumber = goalNumber.divide(goalNumber); } //If for some reason the goalNumber is not 1 throw an error if(!goalNumber.equals(BigInteger.ONE)){ throw new InvalidResult("The factor was not 1: " + goalNumber); } //Return the list of factors return factors; } //This function returns all the divisors of goalNumber public static List getDivisors(int goalNumber){ return ArrayAlgorithms.longToInt(getDivisors((long)goalNumber)); } public static List getDivisors(long goalNumber){ HashSet divisors = new HashSet<>(); //Start by checking that the number is positive if(goalNumber <= 0){ return new ArrayList<>(); } else{ divisors.add(1L); divisors.add(goalNumber); } //Start at 3 and loop through all numbers < sqrt(goalNumber) looking for a number that divides it evenly Double topPossibleDivisor = Math.ceil(Math.sqrt(goalNumber)); for(long possibleDivisor = 2L;possibleDivisor <= topPossibleDivisor;++possibleDivisor){ //If you find one add it and the number it creates to the list if((goalNumber % possibleDivisor) == 0){ long possibleDivisor2 = goalNumber / possibleDivisor; divisors.add(possibleDivisor); divisors.add(possibleDivisor2); } } ArrayList divisorList = new ArrayList<>(divisors); //Sort the list before returning it for neatness Collections.sort(divisorList); //Return the list return divisorList; } public static List getDivisors(BigInteger goalNumber){ HashSet divisors = new HashSet<>(); //Start by checking that the number is positive if(goalNumber.compareTo(BigInteger.valueOf(0)) <= 0){ return new ArrayList<>(); } else{ divisors.add(BigInteger.valueOf(1)); divisors.add(goalNumber); } //Start at 3 and loop through all numbers < sqrt(goalNumber) looking for a number that divides it evenly BigInteger topPossibleDivisor = goalNumber.sqrt(); for(BigInteger possibleDivisor = BigInteger.TWO;possibleDivisor.compareTo(topPossibleDivisor) <= 0;possibleDivisor = possibleDivisor.add(BigInteger.valueOf(1))){ //If you find one add it and the number it creates to the list if(goalNumber.mod(possibleDivisor).equals(BigInteger.valueOf(0))){ BigInteger possibleDivisor2 = goalNumber.divide(possibleDivisor); divisors.add(possibleDivisor); divisors.add(possibleDivisor2); } } ArrayList divisorList = new ArrayList<>(divisors); //Sort the list before returning it for neatness Collections.sort(divisorList); //Return the list return divisorList; } //This function returns the goalSubscript'th Fibonacci number public static int getFib(int goalSubscript){ return (int)getFib((long)goalSubscript); } public static long getFib(long goalSubscript){ //Setup the variables long[] fibNums = {1L, 1L, 0L}; //A list to keep track of the Fibonacci numbers. It need only be 3 long because we only need the one we are working on and the last 2 //If the number is <= 0 return 0 if(goalSubscript <= 0){ return 0L; } //Loop through the list, generating Fibonacci numbers until it finds the correct subscript int fibLoc; for(fibLoc = 2;fibLoc < goalSubscript;++fibLoc){ fibNums[fibLoc % 3] = fibNums[(fibLoc - 1) % 3] + fibNums[(fibLoc - 2) % 3]; } //Return the proper number. The location counter is 1 off of the subscript return fibNums[(fibLoc - 1) % 3]; } public static BigInteger getFib(BigInteger goalSubscript){ //Setup the variables BigInteger[] fibNums = {BigInteger.valueOf(1), BigInteger.valueOf(1), BigInteger.valueOf(0)}; //A list to keep track of the Fibonacci numbers. It need only be 3 long because we only need the one we are working on and the last 2 //If the number is <= 0 return 0 if(goalSubscript.compareTo(BigInteger.valueOf(0)) <= 0){ return BigInteger.valueOf(0); } //Loop through the list, generating Fibonacci numbers until it finds the correct subscript int fibLoc; for(fibLoc = 2;goalSubscript.compareTo(BigInteger.valueOf(fibLoc)) > 0;++fibLoc){ fibNums[fibLoc % 3] = fibNums[(fibLoc - 1) % 3].add(fibNums[(fibLoc - 2) % 3]); } //Return the proper number. The location counter is 1 off of the subscript return fibNums[(fibLoc - 1) % 3]; } //This function returns a list of all Fibonacci numbers <= goalNumber public static List getAllFib(int goalNumber){ return ArrayAlgorithms.longToInt(getAllFib((long) goalNumber)); } public static List getAllFib(long goalNumber){ //Setup the variables ArrayList fibNums = new ArrayList<>(); //A list to save the Fibonacci numbers //If the number is <= 0 return an empty list if(goalNumber <= 0){ return fibNums; } //This means that at least 2 1's are elements fibNums.add(1L); fibNums.add(1L); //Loop to generate the rest of the Fibonacci numbers while(fibNums.get(fibNums.size() - 1) <= goalNumber){ fibNums.add(fibNums.get(fibNums.size() - 1) + fibNums.get(fibNums.size() - 2)); } //At this point the most recent number is > goalNumber, so remove it and return the rest of the list fibNums.remove(fibNums.size() - 1); return fibNums; } public static List getAllFib(BigInteger goalNumber){ //Setup the variables ArrayList fibNums = new ArrayList<>(); //A list to save the Fibonacci numbers //If the number is <= 0 return an empty list if(goalNumber.compareTo(BigInteger.valueOf(0)) <= 0){ return fibNums; } //This means that at least 2 1's are elements fibNums.add(BigInteger.valueOf(1)); fibNums.add(BigInteger.valueOf(1)); //Loop to generate the rest of the Fibonacci numbers while(fibNums.get(fibNums.size() - 1).compareTo(goalNumber) <= 0){ fibNums.add(fibNums.get(fibNums.size() - 1).add(fibNums.get(fibNums.size() - 2))); } //At this point the most recent number is > goalNumber, so remove it and return the rest of the list fibNums.remove(fibNums.size() - 1); return fibNums; } //This function returns the factorial of the number passed to it public static int factorial(int num) throws InvalidParameterException{ return (int)factorial((long)num); } public static long factorial(long num) throws InvalidParameterException{ long fact = 1L; //The value of the factorial //If the number passed in is < 0 throw an exception if(num < 0){ throw new InvalidParameterException(FACTORIAL_NEGATIVE_MESSAGE); } //Loop through every number up to and including num and add the product to the factorial for(long cnt = 2L;cnt <= num;++cnt){ fact *= cnt; } return fact; } public static BigInteger factorial(BigInteger num) throws InvalidParameterException{ BigInteger fact = BigInteger.valueOf(1L); //If the number passed in is < 0 throw an exception if(num.compareTo(BigInteger.ZERO) < 0){ throw new InvalidParameterException(FACTORIAL_NEGATIVE_MESSAGE); } //Loop through every number up to and including num and add the product to the factorial for(BigInteger cnt = BigInteger.TWO;cnt.compareTo(num) <= 0;cnt = cnt.add(BigInteger.ONE)){ fact = fact.multiply(cnt); } return fact; } //This function returns the GCD of the two numbers sent to it public static int gcd(int num1, int num2){ return (int)gcd((long)num1, (long)num2); } public static long gcd(long num1, long num2){ while((num1 != 0) && (num2 != 0)){ if(num1 > num2){ num1 %= num2; } else{ num2 %= num1; } } return num1 | num2; } public static BigInteger gcd(BigInteger num1, BigInteger num2){ while(!num1.equals(BigInteger.ZERO) && !num2.equals(BigInteger.ZERO)){ if(num1.compareTo(num2) > 0){ num1 = num1.mod(num2); } else{ num2 = num2.mod(num1); } } return num1.or(num2); } //Converts a number to its binary equivalent public static String toBin(long num){ //Convert the number to binary string return Long.toBinaryString(num); } public static String toBin(BigInteger num){ //Conver the number to binary string return num.toString(2); } }