I have to create a class that extends RandomGenerator and produces a random prime number each time the user enters an interval in the main program.
I have created the constructors and the isPrime method but I can't figure out what to do next.
That's how far I got. I am sure there are mistakes in this, but I just can't see them.
public class RandomGeneratorImproved extends RandomGenerator {
public RandomGeneratorImproved(int prime) {
int startp=0;
int tillp=prime-1;
}
public RandomGeneratorImproved(int lowp,int upperp) {
int startp=lowp;
int tillp=upperp;
}
public boolean isPrime(int startp,int tillp) {
int prime=rgen.nextInt(startp,tillp);
int n=0;
if (prime<=1) {
return false;
} else if (prime<=3) {
return true;
} else if (prime%2==0 || prime%3==0){
return false;
}
for (int i=5;i<(prime/i);i+=6) {
if (prime%i==0) {
return false;
}
}
return true;
}
private RandomGenerator rgen= RandomGenerator.getInstance();
}
Notes:
If the user enters only one number ( lets say: x ) then the interval will be (0,x).In other words we have to create either two methods either two constructors.
For example:
public int nextPrime(int n) or public int nextPrime(int low,int high)
I am not allowed to use arrays (or other ready-made methods that make the problem way easier).
I searched everything that involved Random Prime Numbers Generators but I couldn't find anything similar to this.
Some advice on how to improve and use the class.
I have to create a class that extends RandomGenerator and produces a random prime number each time the user enters an interval in the main program.
That tells me that the instance of your class is not associated with a range at its creation. The range is given only on the user's demand to generate a prime. As such, I would
Create an empty constructor and to whatever initialization there is to do there.
Add overloaded methods public int generatePrime(int high) and public int generatePrime(int low, int high). Generally, overloaded methods with less arguments (less data) should just call the most specific method by completing the needed data (see code below).
The method name isPrime suggests that it should check if a single given int is a prime or not. I would make it boolean isPrime(int primeQ).
The only step left is to figure out what ints to give to isPrime from the specified range. Since the superclass has a method that generates a random int in the range, you can pass it to isPrime to check if it is a prime. If it is, return it, otherwise try again. Note that this is extremely inefficient, but with the lack of tools and info this is the simplest bridge I could find.
Here is the code:
public class RandomGeneratorImproved extends RandomGenerator {
private RandomGenerator rgen;
public RandomGeneratorImproved() {
rgen = RandomGenerator.getInstance();
}
public int generatePrime(int prime) {
return generatePrime(0, prime - 1);
}
public int generatePrime(int lowp, int upperp) {
int prime = rgen.nextInt(lowp, upperp);
while (!isPrime(prime))
prime = rgen.nextInt(lowp, upperp);
return prime;
}
public boolean isPrime(int prime) {
int n = 0; // <------ this is not used
if (prime <= 1) {
return false;
}
else if (prime <= 3) {
return true;
}
else if (prime % 2 == 0 || prime % 3 == 0) {
return false;
}
for (int i = 5; i < (prime / i); i += 6) {
if (prime % i == 0) {
return false;// "random number"+prime+"is not a prime number";
}
}
return true;// "random number"+prime+"is a prime number";
}
}
Note that the line int n = 0; gives a warning that n is never used. You might want to remove it.
The usage would be:
RandomGeneratorImproved rpg = new RandomGeneratorImproved();
int generatedPrime = rpg.generatePrime(6, 30);
int generatedPrime2 = rpg.generatePrime(30); // same as rpg.generatePrime(1, 30)
The rejection method - generating a random number in the range of interest, checking whether it satisfies the target criteria and returning it if it does else repeating the process - has the advantage that it produces perfectly unbiased results. Its disadvantage is performance (or lack thereof).
Also, trial division is just about the slowest primality test method known to Man. Depending on the use of the 'random primes', different approaches are possible. They all require the prime factors up to the square root of the upper end of the range to be available in some form, but so does Trial Division.
Alternative 1: The Peepholes of Eratosthenes
Given that the target range seems to be limited to small integers, the following approach is feasible: draw a random number k, sieve the range [max(2, k - 335), k] using a windowed Sieve of Eratosthenes and return the highest prime in that range. This works because the gaps between primes up to 4,302,407,359 are no wider than 336. Hence the tiny window ('peephole') must necessarily contain a prime.
Disadvantage: the resulting distribution of primes is uneven (biased). For example, the number 2 will only be returned if k == 2 since the next higher prime (3) is right next to it. By contrast, the number 3,842,610,773 is followed by 335 non-primes and so the probability of its being drawn is 336 times as high as that for the number 2. However, proving the bias by looking at the output isn't easy, and for automated testers it should be near impossible.
Caveat: in this context the sieving always needs to process all prime factors up to the square root of k, which involves one modulo division per prime for computing the start offset within the window. By contrast, Trial Division can reject more than 85% of all composites based on just the first dozen primes alone. Hence there's probably no situation where Peepholes actually has an advantage over Trial Division.
Alternative 2: The Lazy Segmented Eratosthenes
Sieving the first 2^31 numbers takes quite a bit of CPU time (about 1 CPU second in C++, lots more in Java), and a lot of that effort goes to waste unless random primes are needed in great bulk, to the tune of many millions. If only a tiny handful of random primes is needed then Trial Division is indeed the way to go but if more are desired then a lazy approach to segmented sieving can help.
Pick a segment size that does not exceed the size of the L1 cache and create a segment cache array that covers the whole target range. After drawing a random k, retrieve the reference for the corresponding segment from the cache; if it is nil, sieve the segment and store the reference in the appropriate cache slot. Then you have a segment reference in any case, so you can test the primality of k by checking the bit (k >> 1) % segment_size in the segment, assuming an odds-only sieve.
Segments should be packed bitmaps representing odd numbers, and % segment_size can be computed by masking if the segment size is a power of 2. This way you always get an answer quickly without the long wait for sieving the whole range in one go. And the efficiency goes up when you need it to (i.e. when you are drawing lots of random primes) because the cache fills itself, causing more and more primality queries to be satisfied by already-existing segments.
Unlike the Peephole method, this gives a perfectly unbiased distribution (which is kind of obvious, since it only replaces the primality test but not the actual method of drawing primes).
There's some more info in a post on Code Review that discusses the challenge of drawing 100 random primes.
Related
I'am doing a practice interview question from HackerRank Coin Change
I got stuck and I'm trying to understand a Solution to this problem. Here is the recursive solution to this problem.(with my comments to understand it)
public static int numWays(int[] coins, int sumTo) {
return numWaysWhichCoin(coins, sumTo, 0);
}
private static int numWaysWhichCoin(int[] coins, int sumTo, int whichCoin) {
if(sumTo == 0) {
//empty set
return 1;
} else if(sumTo < 0) {
//no way to form a negative sum with positive coin values
return 0;
} else {
//sumTo is positive
//case gone through all the coins but still a positive sum. Impossible
if(sumTo > 0 && whichCoin == coins.length) {
return 0;
}
//with and without. With, you can keep using the same coin
return numWaysWhichCoin(coins, sumTo - coins[whichCoin], whichCoin) + numWaysWhichCoin(coins, sumTo, whichCoin + 1);
}
}
The author states that the algorithm runs in O(2n) time complexity. From my experience in interviews, you are expected to justify your answers.
How wold you justify this time complexity? From my previous work to showing algorithms run in O(2n) time, I would use recurrence relations, like(Fibonacci) T(n) = T(n-1) + T(n-2) +c <= 2T(n-1) + c, T(1) = d, but I can't derive a recurrence relation like that from here. Is there another way of going about this justification?
The two recursive calls make it act like a binaric tree that grows in 2 n rate.
Your algorithm as far as complexity is identical to Fibonacci recursive algorithem. So you can look and find the many answers and explenations and even proofs why recursive Fibonacci is from the order of 2 n.
Suppose there are R different combinations (the requested result).
The number of coins of the i-th coin (0<=i<=M-1) used in a specific solution r (0<=r<=R-1) is C(i, r). So for each r in 0...R-1 we have C(0,r)+C(1,r)+....C(M-1,r)=N.
The maximum value of C(i, r) for each r in 0...R-1 is max_c(i)=floor(N/Vi) (Vi is the value of coin i), which less or equal to N.
The sum of c_max(i) where i=0..M-1 is <= N*M. So the total number of individual coins used in all the combinations is O(NM).
The algorithm you presented simply iterates all the sub-groups of the group above of c_max(i) individual coins for each coin value Vi, which O(2^(NM)).
I'm try to see if large numbers are prime or not, number whose length are 11. Here is the code I am using:
private static boolean isPrime(BigInteger eval_number){
for(int i=2;i < eval_number.intValue();i++) {
if(eval_number.intValue() % i==0)
return false;
}
return true;
}
Now the number I'm inspecting in the debugger is eval_number which equals 11235813213. However when I inspect the eval_number.intValue() in the debugger instead of the value being 11235813213 the value is -1649088675. How is this happening? Also what would be a better way in inspecting large numbers to see if they are prime?
The strange value is a result of an overflow. The number held by the BigInteger instance is greater than 2^31-1 (Integer.MAX_VALUE) thus it can't be represented by an int. For the primcheck: BigInteger provides isProbablePrime(int) and there are several other fast (more or less) algorithms that allow to check whether a number is a primnumber with a given failure-rate. If you prefer 100% certainty you can optimize your code by reducing the upper-bounds for numbers to check to sqrt(input) and increasing the step-size by two. Or generate a prim-table, if the algorithm is used several times.
intValue() returns an integer equivalent for the given BigInteger number.
Since you are passing the value 11235813213, which is much larger than Integer.MAX_VALUE(maximum possible value for an int variable), which is 2147483647. So , it resulted in overflowing of the integer.
Also what would be a better way in inspecting large numbers to see if
they are prime?
You should use only BigInteger numbers for finding out large primes. Also, check this question (Determining if a BigInteger is Prime in Java) which I asked a year ago.
As others have said the number you are checking is ouside of the range of int.
You could use a long, but that only delays the problem, it will still fail on numbers beyond long's range.
The solution is to use BigInteger arithmetic :
private static boolean isPrime(BigInteger eval_number) {
for (BigInteger i = BigInteger.valueOf(2); i.compareTo(eval_number) < 0; i = i.add(BigInteger.ONE)) {
if (eval_number.mod(i).equals(BigInteger.ZERO)) {
return false;
}
}
return true;
}
That is just a correction of the inmediate problem your question is about. There are still things to improve there. Checking for being prime can be made more efficient. You don't have to check even numbers except 2 and you only need to check till the square root of the number in question.
You convert BigInteger to 32bit integer. If it is bigger than 2^31, it will return incorrect value. You need to do all the operations over BigInteger instances. I assume that you use BigInteger because of long being insufficient for other cases, but for number you stated as an example would be use of long instead of int sufficient. (long will be enough for numbers up to 2^63).
You have to make all operations with BigInteger, without converting it to int :
private static boolean isPrime(BigInteger eval_number) {
for (BigInteger i = BigInteger.valueOf(2); i.compareTo(eval_number) < 0; i = i.add(BigInteger.ONE)) {
if (eval_number.divideAndRemainder(i)[1].equals(BigInteger.ZERO)) {
System.out.println(i);
return false;
}
}
return true;
}
If you want to check whether a BigInteger is Prime or not you can use java.math.BigInteger.isProbablePrime(int certainty) it will returns true if this BigInteger is probably prime, false if it's definitely composite. If certainty is ≤ 0, true is returned.
I'm trying to solve problem 3 from http://projecteuler.net. However, when I run thing program nothing prints out.
What am I doing wrong?
Problem: What is the largest prime factor of the number 600851475143 ?
public class project_3
{
public boolean prime(long x) // if x is prime return true
{
boolean bool = false;
for(long count=1L; count<x; count++)
{
if( x%count==0 )
{
bool = false;
break;
}
else { bool = true; }
}
return bool;
}
public static void main(String[] args)
{
long ultprime = 0L; // largest prime value
project_3 object = new project_3();
for(long x=1L; x <= 600851475143L; x++)
{
if( object.prime(x)==true )
{
ultprime = ((x>ultprime) ? x : ultprime);
}
}
System.out.println(ultprime);
}
}
Not only does your prime checking function always return false; even if it were functioning properly, your main loop does not seek the input number's factors at all, but rather just the largest prime smaller or equal to it. In pseudocode, your code is equivalent to:
foo(n):
x := 0 ;
foreach d from 1 to n step 1:
if is_prime(d): // always false
x := d
return x // always 0
is_prime(d):
not( d % 1 == 0 ) // always false
But you don't need the prime checking function here at all. The following finds all factors of a number, by trial division:
factors(n):
fs := []
d := 2
while ( d <= n/d ):
if ( n % d == 0 ): { n := n/d ; fs := append(fs,d) }
else: { d := d+1 }
if ( n > 1 ): { fs := append(fs, n) }
return fs
The testing for divisibility is done only up to the square root of the number. Each factor, as it is found, is divided out of the number being factorized, thus further reducing the run time. Factorization of the number in question runs instantly, taking just 1473 iterations.
By construction all the factors thus found are guaranteed to be prime (that's why no prime checking is needed). It is crucial to enumerate the possible divisors in ascending order for this to happen1. Ascending order is also the most efficient, because any given number is more likely to have smaller prime factor than larger one. Enumerating the primes instead of odds, though not necessary, will be more efficient if you have an efficient way of getting those primes, to test divide by.
It is trivial to augment the above to find the largest factor: just implement append as
append(fs,d):
return d
1
because then for any composite divisor d of the original number being factorized, when we'll reach d, we will have already divided its prime factors out of the original number, and so the reduced number will have no common prime factors with it, i.e. d won't divide the reduced number even though it divides the original.
Two things:
1) You are starting count at 1 instead of 2. All integers are divisible by 1.
2) You are running an O(n^2) algorithm against a rather large N (or at least you will be once you fix point #1). The runtime will be quite long.
The whole point of Project Euler is that the most obvious approaches to finding the answer will take so long to compute that they aren't worth running. That way you learn to look for the less obvious, more efficient approaches.
Your approach is technically correct in terms of whether or not it is capable of computing the largest prime of some number. The reason you aren't seeing anything print out is that your algorithm is not capable of solving the problem quickly.
The way you've designed this, it'll take somewhere around 4,000,000 years to finish.
If you replaced the 600851475143 number with say 20 it would be able to finish fairly quickly. But you have the 600 billion number, so it's not that simple.
Suppose I have a method to calculate combinations of r items from n items:
public static long combi(int n, int r) {
if ( r == n) return 1;
long numr = 1;
for(int i=n; i > (n-r); i--) {
numr *=i;
}
return numr/fact(r);
}
public static long fact(int n) {
long rs = 1;
if(n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
}
return rs;
}
As you can see it involves factorial which can easily overflow the result. For example if I have fact(200) for the foctorial method I get zero. The question is why do I get zero?
Secondly how do I deal with overflow in above context? The method should return largest possible number to fit in long if the result is too big instead of returning wrong answer.
One approach (but this could be wrong) is that if the result exceed some large number for example 1,400,000,000 then return remainder of result modulo
1,400,000,001. Can you explain what this means and how can I do that in Java?
Note that I do not guarantee that above methods are accurate for calculating factorial and combinations. Extra bonus if you can find errors and correct them.
Note that I can only use int or long and if it is unavoidable, can also use double. Other data types are not allowed.
I am not sure who marked this question as homework. This is NOT homework. I wish it was homework and i was back to future, young student at university. But I am old with more than 10 years working as programmer. I just want to practice developing highly optimized solutions in Java. In our times at university, Internet did not even exist. Today's students are lucky that they can even post their homework on site like SO.
Use the multiplicative formula, instead of the factorial formula.
Since its homework, I won't want to just give you a solution. However a hint I will give is that instead of calculating two large numbers and dividing the result, try calculating both together. e.g. calculate the numerator until its about to over flow, then calculate the denominator. In this last step you can chose the divide the numerator instead of multiplying the denominator. This stops both values from getting really large when the ratio of the two is relatively small.
I got this result before an overflow was detected.
combi(61,30) = 232714176627630544 which is 2.52% of Long.MAX_VALUE
The only "bug" I found in your code is not having any overflow detection, since you know its likely to be a problem. ;)
To answer your first question (why did you get zero), the values of fact() as computed by modular arithmetic were such that you hit a result with all 64 bits zero! Change your fact code to this:
public static long fact(int n) {
long rs = 1;
if( n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
System.out.println(rs);
}
return rs;
}
Take a look at the outputs! They are very interesting.
Now onto the second question....
It looks like you want to give exact integer (er, long) answers for values of n and r that fit, and throw an exception if they do not. This is a fair exercise.
To do this properly you should not use factorial at all. The trick is to recognize that C(n,r) can be computed incrementally by adding terms. This can be done using recursion with memoization, or by the multiplicative formula mentioned by Stefan Kendall.
As you accumulate the results into a long variable that you will use for your answer, check the value after each addition to see if it goes negative. When it does, throw an exception. If it stays positive, you can safely return your accumulated result as your answer.
To see why this works consider Pascal's triangle
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
which is generated like so:
C(0,0) = 1 (base case)
C(1,0) = 1 (base case)
C(1,1) = 1 (base case)
C(2,0) = 1 (base case)
C(2,1) = C(1,0) + C(1,1) = 2
C(2,2) = 1 (base case)
C(3,0) = 1 (base case)
C(3,1) = C(2,0) + C(2,1) = 3
C(3,2) = C(2,1) + C(2,2) = 3
...
When computing the value of C(n,r) using memoization, store the results of recursive invocations as you encounter them in a suitable structure such as an array or hashmap. Each value is the sum of two smaller numbers. The numbers start small and are always positive. Whenever you compute a new value (let's call it a subterm) you are adding smaller positive numbers. Recall from your computer organization class that whenever you add two modular positive numbers, there is an overflow if and only if the sum is negative. It only takes one overflow in the whole process for you to know that the C(n,r) you are looking for is too large.
This line of argument could be turned into a nice inductive proof, but that might be for another assignment, and perhaps another StackExchange site.
ADDENDUM
Here is a complete application you can run. (I haven't figured out how to get Java to run on codepad and ideone).
/**
* A demo showing how to do combinations using recursion and memoization, while detecting
* results that cannot fit in 64 bits.
*/
public class CombinationExample {
/**
* Returns the number of combinatios of r things out of n total.
*/
public static long combi(int n, int r) {
long[][] cache = new long[n + 1][n + 1];
if (n < 0 || r > n) {
throw new IllegalArgumentException("Nonsense args");
}
return c(n, r, cache);
}
/**
* Recursive helper for combi.
*/
private static long c(int n, int r, long[][] cache) {
if (r == 0 || r == n) {
return cache[n][r] = 1;
} else if (cache[n][r] != 0) {
return cache[n][r];
} else {
cache[n][r] = c(n-1, r-1, cache) + c(n-1, r, cache);
if (cache[n][r] < 0) {
throw new RuntimeException("Woops too big");
}
return cache[n][r];
}
}
/**
* Prints out a few example invocations.
*/
public static void main(String[] args) {
String[] data = ("0,0,3,1,4,4,5,2,10,0,10,10,10,4,9,7,70,8,295,100," +
"34,88,-2,7,9,-1,90,0,90,1,90,2,90,3,90,8,90,24").split(",");
for (int i = 0; i < data.length; i += 2) {
int n = Integer.valueOf(data[i]);
int r = Integer.valueOf(data[i + 1]);
System.out.printf("C(%d,%d) = ", n, r);
try {
System.out.println(combi(n, r));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Hope it is useful. It's just a quick hack so you might want to clean it up a little.... Also note that a good solution would use proper unit testing, although this code does give nice output.
You can use the java.math.BigInteger class to deal with arbitrarily large numbers.
If you make the return type double, it can handle up to fact(170), but you'll lose some precision because of the nature of double (I don't know why you'd need exact precision for such huge numbers).
For input over 170, the result is infinity
Note that java.lang.Long includes constants for the min and max values for a long.
When you add together two signed 2s-complement positive values of a given size, and the result overflows, the result will be negative. Bit-wise, it will be the same bits you would have gotten with a larger representation, only the high-order bit will be truncated away.
Multiplying is a bit more complicated, unfortunately, since you can overflow by more than one bit.
But you can multiply in parts. Basically you break the to multipliers into low and high halves (or more than that, if you already have an "overflowed" value), perform the four possible multiplications between the four halves, then recombine the results. (It's really just like doing decimal multiplication by hand, but each "digit" is, say, 32 bits.)
You can copy the code from java.math.BigInteger to deal with arbitrarily large numbers. Go ahead and plagiarize.
I'm looking to randomize a BigInteger. The intent is to pick a number from 1 to 8180385048. Though, from what I noticed, the BigInteger(BitLen, Random) does it from n to X2-1, I'd want some unpredictable number. I tried to make a method that would do it, but I keep running into bugs and have finally given in to asking on here. :P Does anyone have any suggestions on how to do this?
Judging from the docs of Random.nextInt(int n) which obviously needs to solve the same problem, they seem to have concluded that you can't do better than "resampling if out of range", but that the penalty is expected to be negligible.
From the docs:
The algorithm is slightly tricky. It rejects values that would result in an uneven distribution (due to the fact that 231 is not divisible by n). The probability of a value being rejected depends on n. The worst case is n=230+1, for which the probability of a reject is 1/2, and the expected number of iterations before the loop terminates is 2.
I'd suggest you simply use the randomizing constructor you mentioned and iterate until you reach a value that is in range, for instance like this:
public static BigInteger rndBigInt(BigInteger max) {
Random rnd = new Random();
do {
BigInteger i = new BigInteger(max.bitLength(), rnd);
if (i.compareTo(max) <= 0)
return i;
} while (true);
}
public static void main(String... args) {
System.out.println(rndBigInt(new BigInteger("8180385048")));
}
For your particular case (with max = 8180385048), the probability of having to reiterate, even once, is about 4.8 %, so no worries :-)
Make a loop and get random BigIntegers of the minimum bit length that covers your range until you obtain one number in range. That should preserve the distribution of random numbers.
Reiterating if out of range, as suggested in other answers, is a solution to this problem. However if you want to avoid this, another option is to use the modulus operator:
BigInteger i = new BigInteger(max.bitLength(), rnd);
i = i.mod(max); // Now 0 <= i <= max - 1
i = i.add(BigInteger.ONE); // Now 1 <= i <= max