Can't Generate Large Prime Numbers - java

I'm trying to generate large prime numbers in Java. I use BigIntegers for this. Here is my code to generate and store 10 prime numbers inside an array.
public static void primeGenerator() {
BigInteger[] primeList = new BigInteger[10];
BigInteger startLine = new BigInteger("10");
int startPower = 6;
BigInteger endLine = new BigInteger("10");
int endPower = 9;
int j = 0;
for (BigInteger i = fastExp(startLine,startPower);
i.compareTo(fastExp(endLine,endPower)) <= 0;
i = i.add(BigInteger.ONE)) {
if (checkPrimeFermat(i) == true && j < 10) {
primeList[j] = i;
j++;
}
}
System.out.println(primeList[0]);
System.out.println(primeList[1]);
System.out.println(primeList[2]);
System.out.println(primeList[3]);
System.out.println(primeList[4]);
System.out.println(primeList[5]);
System.out.println(primeList[6]);
System.out.println(primeList[7]);
System.out.println(primeList[8]);
System.out.println(primeList[9]);
}
I wrote my own fastExp function to generate numbers faster. Here are my other functions.
public static BigInteger getRandomFermatBase(BigInteger n)
{
Random rand = new Random();
while (true)
{
BigInteger a = new BigInteger (n.bitLength(), rand);
if (BigInteger.ONE.compareTo(a) <= 0 && a.compareTo(n) < 0)
{
return a;
}
}
}
public static boolean checkPrimeFermat(BigInteger n)
{
if (n.equals(BigInteger.ONE))
return false;
for (int i = 0; i < 10; i++)
{
BigInteger a = getRandomFermatBase(n);
a = a.modPow(n.subtract(BigInteger.ONE), n);
if (!a.equals(BigInteger.ONE))
return false;
}
return true;
}
public static void main(String[] args) throws IOException
{
primeGenerator();
}
public static BigInteger fastExp (BigInteger x, int n){
BigInteger result=x;
int pow2=powof2leN(n);
int residue= n-pow2;
for(int i=1; i<pow2 ; i=i*2){
result=result.multiply(result);
}
for(int i=0 ; i<residue; i++){
result=result.multiply(x);
}
return result;
}
private static int powof2leN(int n) {
for(int i=1; i<=n; i=i*2){
if(i*2>2)
return 1;
}
return 0;
}
}
So the problem is when I try it with small numbers (for example startPower=3, endPower=5) it generates and prints prime numbers. But when I try it with big numbers (for example startPower=5, endPower=7) it doesn't generate anything. How can I improve my code to work with large numbers?
Thank you

First of all, I would like to point out that you did not write this code. You stole it from here and claimed that you wrote it, which is incredibly unethical.
The code is correct. It's just slow. As you increase the power, the code takes increasingly longer. There are two reasons why this occurs:
The Fermat test takes increasingly longer to apply.
BigInteger operations take increasingly longer to execute.
The Fermat test grows like O(k × log2n × log log n × log log log n). BigInteger's addition and subtraction grow like O(n). Obviously, BigInteger is what is slowing you down.
Below is a profile of your code with the power set from 5 to 7.
If you want your code to produce larger and larger primes, you should focus on reducing the number of operations you do on BigIntegers. Here is one such improvement:
Take n.subtract(BigInteger.ONE) outside of your for loop. The result does not need to be calculated many times.
Further suggestions will have to come from the Mathematics folks over on Mathematics Stack Exchange.

Here is a much simpler solution for finding large primes -
BigInteger big = new BigInteger("9001");//or whatever big number you want to start with
BigInteger[] primes = new BigInteger[10];
for(int i=0;i<10;i++){
primes[i]=big=big.nextProbablePrime();
}
It has some limitations outlined here, but based on your code it should be more than enough.

you can use BigInteger(int bitLength, int certainty, Random rnd) constructor
BigInteger b= new BigInteger(20, 1, new Random());
It will generate a prime number for you. bitLength specifies the number of digits you want in your BigInteger, certainity specifies the amount of certainity you want that your BigInteger should be prime.

Related

Rabin-Miller in Java

I got a function RSA program using BigInteger class.
However I generated my primes using the built in function. Instead, im asked to generate two primes, p and q via a Rabin-Miller test
The rabin-miller will run separately, I will generate two primes then enter them as static numbers in my RSA program, so they will be 2 separate programs.
The pseudo code for rabin-miller on wikipedia:
import java.math.BigInteger;
import java.util.Random;
public class MillerRabin {
private static final BigInteger ZERO = BigInteger.ZERO;
private static final BigInteger ONE = BigInteger.ONE;
private static final BigInteger TWO = new BigInteger("2");
private static final BigInteger THREE = new BigInteger("3");
public static boolean isProbablePrime(BigInteger n, int k) {
if (n.compareTo(ONE) == 0)
return false;
if (n.compareTo(THREE) < 0)
return true;
int s = 0;
BigInteger d = n.subtract(ONE);
while (d.mod(TWO).equals(ZERO)) {
s++;
d = d.divide(TWO);
}
for (int i = 0; i < k; i++) {
BigInteger a = uniformRandom(TWO, n.subtract(ONE));
BigInteger x = a.modPow(d, n);
if (x.equals(ONE) || x.equals(n.subtract(ONE)))
continue;
int r = 0;
for (; r < s; r++) {
x = x.modPow(TWO, n);
if (x.equals(ONE))
return false;
if (x.equals(n.subtract(ONE)))
break;
}
if (r == s) // None of the steps made x equal n-1.
return false;
}
return true;
}
private static BigInteger uniformRandom(BigInteger bottom, BigInteger top) {
Random rnd = new Random();
BigInteger res;
do {
res = new BigInteger(top.bitLength(), rnd);
} while (res.compareTo(bottom) < 0 || res.compareTo(top) > 0);
return res;
}
public static void main(String[] args) {
// run with -ea to enable assertions
String[] primes = {"1", "3", "3613", "7297",
"226673591177742970257407", "2932031007403"};
String[] nonPrimes = {"3341", "2932021007403",
"226673591177742970257405"};
int k = 40;
for (String p : primes)
assert isProbablePrime(new BigInteger(p), k);
for (String n : nonPrimes)
assert !isProbablePrime(new BigInteger(n), k);
}
}
Now my questions:
Out of this I will have to generate x number of primes, out of x number bitlength.
So lets say: generate 2 prime numbers out of 512 bits. Any idea how this could be done?
Also im supposed to generate 20 random a.
I guess I dont need the ending of the program or the code with top bottom
Just the mathetatical operations that represents rabin-miller and then somehow produce primes out of X bitlength
How would I do this?
OK, so you want to have a big integer in the range 2 ^ 511 to 2 ^ 512 - 1. That way you can be sure that the initial bit is set to one, making it a 512 bit random number. It may be kind of strange, but a 512 bit random number only contains 511 random bits; obviously the first bit cannot be zero because in that case the number is not 512 bits in size.
So to do this you need to generate a number between 0 and 2 ^ 511 - 1, then add 2 ^ 511 to it. Of course you want to use SecureRandom for secure key generation:
public static void main(String[] args) throws Exception {
int bitsize = 512;
SecureRandom rng = new SecureRandom();
for (int i = 0; i < 1000; i++) {
BigInteger randomForBitSize = createRandomForBitSize(bitsize, rng);
System.out.printf("%d : %X%n", randomForBitSize.bitLength(), randomForBitSize);
}
}
private static BigInteger createRandomForBitSize(int bitsize, Random rng) {
BigInteger randomFromZero = new BigInteger(bitsize - 1, rng);
BigInteger lowestNumberBitSize = BigInteger.valueOf(2).pow(bitsize - 1);
BigInteger randomBitSize = lowestNumberBitSize.add(randomFromZero);
return randomBitSize;
}

Using biginteger to find the sequence of sum of powers

Sum(N) =1^1+2^2+3^3+...+N^N
Using Java,
How would I use BigInteger to find the smallest integer N such that the value of Sum(N) is larger than 10^20?
I'm really stuck,please give me some advice
This is what I have so far:
import java.math.BigInteger;
public class PROJECTV1 {
public static void main(String [] args) {
BigInteger bResult= bigFunctionExample_2();
System.out.println(" => result_got:"+ bResult);
System.out.println(); //newline
}// end_main
public static BigInteger bigFunctionExample_2() {
BigInteger bSum = BigInteger.ZERO;
BigInteger bTmp;
String sSum;
// BigInteger bResult =0;
for (int i=1; ; i++) {
bTmp = BigInteger.valueOf(i);
bTmp = bTmp.pow(i); // i^i
bSum = bSum.add(bTmp); // sum = i^i+ (i-1)^(i-1)+ ....
sSum = bSum.toString();
if ( sSum.length() >21) {
System.out.println("i="+i +" bSum ="+bSum);
break;
}//
}//end_for
return bSum; // result
} // end_bigFunctionExample_2
}
Looking at your code, you have a line bTmp.pow(2). That squares the numbers in your series, but you need to raise bTmp to the bTmp power. Java doesn’t seem to want to take a BigInteger as an argument to pow, but you could replace pow with another for loop.
Also, sSum.length() >30 looks like it will only occur if your sum is greater than or equal to 1029. Is there a reason you convert the number to a string each time through the loop, rather than comparing the number to 1020? Perhaps you could put something like bSum > bMax as the test condition in your for loop, rather than leaving it blank and exiting with a break. Then you could make a new BigInteger bMax and set it to 1020 at the start of your code.
For testing, you could set bMax to something small, like 100, and see if your program gives the correct result. You can calculate the first few steps of the series by hand to check your program.
Here is a clue computing some factorials:
import java.math.*;
public class FactorialBig {
public static BigInteger factorial(BigInteger n) {
if (n.equals(BigInteger.ZERO))
return BigInteger.ONE;
else
return n.multiply(factorial(n.subtract(BigInteger.ONE)));
}
public static void main(String[] args) {
for (int n = 0; n < 20; n++) {
BigInteger f = factorial(new BigInteger(new Integer(n).toString()));
System.out.printf("factorial(%2d) = %20s%n", n, f.toString());
}
}
}
You know you should save the above as a file named "FacotrialBig.java".

Statements outside for loop are not being executed

I'm new to Java. I found a website called project eulder and was practicing on a problem.
I don't understand why the following program does not display anything but when I put System.out.println(max); into the for loop it works but displaying all the prime numbers including the biggest. Who do I only the display the biggest prime number?
public class LargestPrimeFactor {
public static void main(String[] args) {
long x = 600851475143L;
int max = 0;
for (int i = 1; i <= x; i++) {
if (x % i == 0)
if (isPrime(i))
max = i;
}
System.out.println(max);
}
public static boolean isPrime(int n) {
for (int i = 2; i < n; i++) {
if (n % i == 0)
return false;
}
return true;
}
}
You have written an infinite loop: 600851475143L is greater than the maximum value that can be stored in an int, so i <= x will always be true.
Changing i and all the other relevant variables to long may solve this issue, but you'll still have to rethink your algorithm. Checking if 600851475143 numbers are prime is just going to take too long.
Hint: once you have found a number that divides x, you can divide x by that number... (Hope this doesn't spoil the fun)

Prime Tester for speed

I was given a homework assignment in Java to create classes that find Prime number and etc (you will see in code better).
My code:
class Primes {
public static boolean IsPrime(long num) {
if (num%2==0){
return false;
}
for (int i=3; i*i<=num;i+=2) {
if (num%i==0) {
return false;
}
}
return true;
} // End boolen IsPrime
public static int[] primes(int min, int max){
int counter=0;
int arcount=0;
for (int i=min;i<max;i++){
if (IsPrime(i)){
counter++;
}
}
int [] arr= new int[counter];
for (int i=min;i<max;i++){
if (IsPrime(i)){
arr[arcount]=i;
arcount++;
}
}
return arr;
} // End Primes
public static String tostring (int [] arr){
String ans="";
for (int i=0; i<arr.length;i++){
ans= ans+arr[i]+ " ";
}
return ans;
}
public static int closestPrime(long num){
long e = 0 , d = 0 , f = num;
for (int i = 2; i <= num + 1 ; i++){
if ((num + 1) % i == 0){
if ((num + 1) % i == 0 && (num + 1) == i){
d = num + 1;
break;
}
num++;
i = 1;
}
}
num = f;
for (int i = 2; i < num; i++){
if ((num - 1) % i == 0){
if ((num - 1) % i == 0 && (num - 1) == i){
e = num - 1;
break;
}
num--;
i = 1;
}
}
num = f;
if (d - num < num - e) System.out.println("Closest Prime: "+d);
else System.out.println("Closest Prime: "+e);
return (int) num;
} // End closestPrime
}//end class
The goal of my code is to be faster (and correct). I'm having difficulties achieving this. Suggestions?
**New code:
class Primes {
public static boolean IsPrime(int num) {
if (num==1){
return false;
}
for (int i=2; i<Math.sqrt(num);i++) {
if (num%i==0) {
return false;
}
}
return true;
}
// End boolen IsPrime
public static int[] primes(int min, int max){
int size=0;
int [] arrtemp= new int[max-min];
for (int i=min;i<max;i++){
if (IsPrime(i)){
arrtemp[size]=i;
size++;
}
}
int [] arr= new int[size];
for (int i=0;i<size;i++){
arr[i]=arrtemp[i];
}
return arr;
}
public static String tostring (int [] arr){
String ans="";
for (int i=0; i<arr.length;i++){
ans= ans+arr[i]+ " ";
}
return ans;
}
public static int closestPrime(int num) {
int count=1;
for (int i=num;;i++){
int plus=num+count, minus=num-count;
if (IsPrime(minus)){
return minus;
}
if (IsPrime(plus)) {
return plus;
}
count=count+1;
}
} // End closestPrime
}//end class
I did try to make it a bit better. what do you think, it can be improved more? (the speed test is still high...)
In your primes function you:
Check if the current number is divisible by two
Check to see if it's prime
Create an array to put your output in.
Check every number in the range again for primality before putting it in your array.
The problem is in the last step. By double-checking whether each number is prime, you're duplicating your most expensive operations.
You could use a dynamic data structure and add prime numbers to it as you find them. That way you only need to check once.
Alternatively, you could create a boolean array which is the size of your input range. Then as you find primes, set the corresponding array value to true.
UPDATE:
There are still a number of improvements you can make, but some will require more work than others to implement. Look at the specifics of your test and see what fits your needs.
Low-hanging fruit:
Use an ArrayList to collect primes as you find them in primes, as opposed to looping over the values twice.
In closestPrime, you're checking every single value on either side of num: half of these are even, thus not prime. You could adapt your code to check only odd numbers for primality.
Trickier to implement:
Try a more advanced algorithm for IsPrime: check out the Sieve of Eratosthenes
Above all, you should spend some time figuring out exactly where the bottlenecks are in your code. Oftentimes performance problems are caused by code we thought was perfectly fine. You might consider looking into the code-profiling options available in your development environment.
You make quite a few calls to isPrime(), each of which is very expensive. Your first step should be to minimize the number of times you do that, since the result doesn't change for any given number, there's no point calling more than once. You can do this with memoization by storing the values once they're computed:
ArrayList<Integer> memoList = new ArrayList<Integer>();
for(int i = 0; i < max; i++) {
if(isPrime(i)) {
memoList.add(i);
}
}
Now memoList holds all the primes you need, up to max, and you can loop over them rapidly without needing to recompute them every time.
Secondly, you can improve your isPrime() method. Your solution loops over every odd number from 3 to sqrt(n), but why not just loop over the primes, now that we know them?
public static boolean IsPrime(long num) {
for(int p : memoList) {
if(num % p == 0) {
return false;
}
}
return true;
}
These changes should dramatically improve how quickly your code runs, but there has been a lot of research into even more efficient ways of calculating primes. The Wikipedia page on Prime Numbers has some very good information on further tactics (prime sieves, in particular) you can experiment with.
Remember that as this is homework you should be sure to cite this page when you turn it in. You're welcome to use and expand upon this code, but not citing this question and any other resources you use is plagiarism.
I see a couple problems with your answer. First, 2 is a prime number. Your first conditional in IsPrime breaks this. Second, in your primes method, you are cycling through all number from min to max. You can safely ignore all negative numbers and all even numbers (as you do in IsPrime). It would make more sense to combine these two methods and save all the extra cycles.

Improving a prime sieve algorithm

I'm trying to make a decent Java program that generates the primes from 1 to N (mainly for Project Euler problems).
At the moment, my algorithm is as follows:
Initialise an array of booleans (or a bitarray if N is sufficiently large) so they're all false, and an array of ints to store the primes found.
Set an integer, s equal to the lowest prime, (ie 2)
While s is <= sqrt(N)
Set all multiples of s (starting at s^2) to true in the array/bitarray.
Find the next smallest index in the array/bitarray which is false, use that as the new value of s.
Endwhile.
Go through the array/bitarray, and for every value that is false, put the corresponding index in the primes array.
Now, I've tried skipping over numbers not of the form 6k + 1 or 6k + 5, but that only gives me a ~2x speed up, whilst I've seen programs run orders of magnitudes faster than mine (albeit with very convoluted code), such as the one here
What can I do to improve?
Edit: Okay, here's my actual code (for N of 1E7):
int l = 10000000, n = 2, sqrt = (int) Math.sqrt(l);
boolean[] nums = new boolean[l + 1];
int[] primes = new int[664579];
while(n <= sqrt){
for(int i = 2 * n; i <= l; nums[i] = true, i += n);
for(n++; nums[n]; n++);
}
for(int i = 2, k = 0; i < nums.length; i++) if(!nums[i]) primes[k++] = i;
Runs in about 350ms on my 2.0GHz machine.
While s is <= sqrt(N)
One mistake people often do in such algorithms is not precomputing square root.
while (s <= sqrt(N)) {
is much, much slower than
int limit = sqrt(N);
while (s <= limit) {
But generally speaking, Eiko is right in his comment. If you want people to offer low-level optimisations, you have to provide code.
update Ok, now about your code.
You may notice that number of iterations in your code is just little bigger than 'l'. (you may put counter inside first 'for' loop, it will be just 2-3 times bigger) And, obviously, complexity of your solution can't be less then O(l) (you can't have less than 'l' iterations).
What can make real difference is accessing memory effectively. Note that guy who wrote that article tries to reduce storage size not just because he's memory-greedy. Making compact arrays allows you to employ cache better and thus increase speed.
I just replaced boolean[] with int[] and achieved immediate x2 speed gain. (and 8x memory) And I didn't even try to do it efficiently.
update2
That's easy. You just replace every assignment a[i] = true with a[i/32] |= 1 << (i%32) and each read operation a[i] with (a[i/32] & (1 << (i%32))) != 0. And boolean[] a with int[] a, obviously.
From the first replacement it should be clear how it works: if f(i) is true, then there's a bit 1 in an integer number a[i/32], at position i%32 (int in Java has exactly 32 bits, as you know).
You can go further and replace i/32 with i >> 5, i%32 with i&31. You can also precompute all 1 << j for each j between 0 and 31 in array.
But sadly, I don't think in Java you could get close to C in this. Not to mention, that guy uses many other tricky optimizations and I agree that his could would've been worth a lot more if he made comments.
Using the BitSet will use less memory. The Sieve algorithm is rather trivial, so you can simply "set" the bit positions on the BitSet, and then iterate to determine the primes.
Did you also make the array smaller while skipping numbers not of the form 6k+1 and 6k+5?
I only tested with ignoring numbers of the form 2k and that gave me ~4x speed up (440 ms -> 120 ms):
int l = 10000000, n = 1, sqrt = (int) Math.sqrt(l);
int m = l/2;
boolean[] nums = new boolean[m + 1];
int[] primes = new int[664579];
int i, k;
while (n <= sqrt) {
int x = (n<<1)+1;
for (i = n+x; i <= m; nums[i] = true, i+=x);
for (n++; nums[n]; n++);
}
primes[0] = 2;
for (i = 1, k = 1; i < nums.length; i++) {
if (!nums[i])
primes[k++] = (i<<1)+1;
}
The following is from my Project Euler Library...Its a slight Variation of the Sieve of Eratosthenes...I'm not sure, but i think its called the Euler Sieve.
1) It uses a BitSet (so 1/8th the memory)
2) Only uses the bitset for Odd Numbers...(another 1/2th hence 1/16th)
Note: The Inner loop (for multiples) begins at "n*n" rather than "2*n" and also multiples of increment "2*n" are only crossed off....hence the speed up.
private void beginSieve(int mLimit)
{
primeList = new BitSet(mLimit>>1);
primeList.set(0,primeList.size(),true);
int sqroot = (int) Math.sqrt(mLimit);
primeList.clear(0);
for(int num = 3; num <= sqroot; num+=2)
{
if( primeList.get(num >> 1) )
{
int inc = num << 1;
for(int factor = num * num; factor < mLimit; factor += inc)
{
//if( ((factor) & 1) == 1)
//{
primeList.clear(factor >> 1);
//}
}
}
}
}
and here's the function to check if a number is prime...
public boolean isPrime(int num)
{
if( num < maxLimit)
{
if( (num & 1) == 0)
return ( num == 2);
else
return primeList.get(num>>1);
}
return false;
}
You could do the step of "putting the corresponding index in the primes array" while you are detecting them, taking out a run through the array, but that's about all I can think of right now.
I wrote a simple sieve implementation recently for the fun of it using BitSet (everyone says not to, but it's the best off the shelf way to store huge data efficiently). The performance seems to be pretty good to me, but I'm still working on improving it.
public class HelloWorld {
private static int LIMIT = 2140000000;//Integer.MAX_VALUE broke things.
private static BitSet marked;
public static void main(String[] args) {
long startTime = System.nanoTime();
init();
sieve();
long estimatedTime = System.nanoTime() - startTime;
System.out.println((float)estimatedTime/1000000000); //23.835363 seconds
System.out.println(marked.size()); //1070000000 ~= 127MB
}
private static void init()
{
double size = LIMIT * 0.5 - 1;
marked = new BitSet();
marked.set(0,(int)size, true);
}
private static void sieve()
{
int i = 0;
int cur = 0;
int add = 0;
int pos = 0;
while(((i<<1)+1)*((i<<1)+1) < LIMIT)
{
pos = i;
if(marked.get(pos++))
{
cur = pos;
add = (cur<<1);
pos += add*cur + cur - 1;
while(pos < marked.length() && pos > 0)
{
marked.clear(pos++);
pos += add;
}
}
i++;
}
}
private static void readPrimes()
{
int pos = 0;
while(pos < marked.length())
{
if(marked.get(pos++))
{
System.out.print((pos<<1)+1);
System.out.print("-");
}
}
}
}
With smaller LIMITs (say 10,000,000 which took 0.077479s) we get much faster results than the OP.
I bet java's performance is terrible when dealing with bits...
Algorithmically, the link you point out should be sufficient
Have you tried googling, e.g. for "java prime numbers". I did and dug up this simple improvement:
http://www.anyexample.com/programming/java/java_prime_number_check_%28primality_test%29.xml
Surely, you can find more at google.
Here is my code for Sieve of Erastothenes and this is actually the most efficient that I could do:
final int MAX = 1000000;
int p[]= new int[MAX];
p[0]=p[1]=1;
int prime[] = new int[MAX/10];
prime[0]=2;
void sieve()
{
int i,j,k=1;
for(i=3;i*i<=MAX;i+=2)
{
if(p[i])
continue;
for(j=i*i;j<MAX;j+=2*i)
p[j]=1;
}
for(i=3;i<MAX;i+=2)
{
if(p[i]==0)
prime[k++]=i;
}
return;
}

Categories