How can I turn this code from long into BigInteger - java

It is a code that gets prime numbers, I have made it as efficient as I could, but the problem is that I can't transform it to BigInteger, as long can't hold that much information; here the code:
public class p3{
static long perfectNumber;
static long mersenne;
public static void main(String[] args) {
long p = 2;
while (true) {
if( p % 2 == 0&&p!=2){
p++;
}
else{
if (isPrime(p) == true) {
mersenne = (long) (Math.pow(2, p) - 1);
if (isPrime(mersenne) == true) {
perfectNumber = (long) Math.pow(2, (p - 1)) * mersenne;
System.out.println(perfectNumber);
}
}
p+=1;
}
}
}
private static boolean isPrime(long testPrime) {
for (long i = 3; i < Math.sqrt(testPrime); i += 2) {
if (testPrime % i == 0) {
return false;
}
}
return true;
}
}

I've tried to use BigInteger but code is not working, as I can't use
BigInteger exponents with pow
You don't need to. The exponents don't need to be nearly as large as the mersenne primes and perfect numbers. They can have their own independent isPrime() test. In fact, they need to be int, instead of long, to satisfy BigInteger.pow().
Below is what you asked for, but may not be what you want. I doubt you'll get more then one additional perfect number beyond your original code due to time constraints which is why #WJS is pushing you in a different direction.
import java.math.BigInteger;
public class p3 {
static BigInteger TWO = new BigInteger("2");
static BigInteger THREE = new BigInteger("3");
public static void main(String[] args) {
int p = 2;
while (true) {
if (isPrime(p)) {
BigInteger mersenne = TWO.pow(p).subtract(BigInteger.ONE);
if (isPrime(mersenne)) {
System.out.println(TWO.pow(p - 1).multiply(mersenne));
}
}
p += (p == 2) ? 1 : 2;
}
}
private static boolean isPrime(BigInteger number) {
if (number.mod(TWO).equals(BigInteger.ZERO)) {
return number.equals(TWO);
}
for (BigInteger i = THREE; number.compareTo(i.multiply(i)) >= 0; i = i.add(TWO)) {
if (number.mod(i).equals(BigInteger.ZERO)) {
return false;
}
}
return true;
}
private static boolean isPrime(int number) {
if (number % 2 == 0) {
return number == 2;
}
for (int i = 3; number >= i * i; i += 2) {
if (number % i == 0) {
return false;
}
}
return true;
}
}
OUTPUT
> java p3
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
2658455991569831744654692615953842176
Your original code outputs 0 in place of the final (37 digit) number above. So the immediate issue really is that long can't hold enough information. But beyond this point, you simply can't calculate fast enough with the above algorithm.
If we do something simple-minded to my above code, like replace this line:
if (isPrime(mersenne)) {
with:
if (mersenne.isProbablePrime(10)) {
The code will spit out the first 20 perfect numbers before slowing to a crawl. Tune the certainty argument of isProbablePrime() as you see fit.

Related

Collatz Conjecture Method - Java

I am just learning to use methods in Java. I am trying to use a method to output the number of steps it takes to get to 1 using the collatz conjecture. Can anyone help me understand better how to execute the method? This is what I have so far:
public static void main(String[] args) {
collatz();
}
public static void collatz(int n) {
n = 20;
int i = 0;
if (n == 1) {
} else if (n % 2 == 0) {
n = (n / 2);
} else {
n = (3 * n + 1);
}
i++;
System.out.println(i);
}
This won't work because "i" is only going to be changed at the end of your code and you are not using recursion or any sort of loop in your code. So, even if it did compile, it won't give the right answer.
This is the recursive way that I've done for you.
public class Cycle {
static int cycle2 (int num) {
if (num == 1) {
return 0;
} else {
if (num % 2 > 0) {
return 1 + cycle2(num * 3 + 1);
} else {
return 1 + cycle2(num / 2);
}
}
}
public static void main(String[] args) {
int num = 14;
System.out.println(cycle2(num));
}
}
As I understand it you're asking about the syntax (rather than the algorithm itself), so here's another version of the above:
public static void main(String[] args) {
// collatz has to be called with a value or it won't compile
collatz(20);
}
public static void collatz(int n) {
int i = 0;
// The following has to occur inside a loop or it'll only occur once
while (n > 1)
{
// The following is what's known as "ternary form" - if the first statement is true, it'll assign the first value. Otherwise it assigns the first value.
// For example,
// int a = (1 == 2 ? 10 : 20);
// will equal 20
n = (n % 2 == 0 ?
(n / 2) : // This value will be assigned if n is even
(3 * n + 1)); // This value will be assigned if n is odd
i++;
}
System.out.println(i);
}
I know this question was asked a long time ago and i had similar problem so this is my solution:
public class Collatz {
public static void main(String[] args) {
collatz();
}
/*If you have (int n) inside method then
when you are calling collatz() you need to have
value inside parentheses-collatz(20), or do simply like I did.
Also you need while loop! It will loop n (20) untill finaly get 1.
Otherwise your code will execute only once
and you will have as a result 1 step to complete instead of 7*/
private static void collatz() {
int n = 20;
int i = 0;
while (n != 1) {
if (n % 2 == 0) {
n = (n / 2);
} else {
n = (3 * n + 1);
}
i++;
}
System.out.println(i);
}
}

Stack overflow exception with recursion

I am trying to make a program which calculates double factorial (example - n=3, => (3!)! = 6! = 720) but i have some issues with recursion bottom and i have stack overflow exception.
public static long df(long n) {
if (n == 1) {
return 1;
} else {
return df(n * df(n - 1));
}
}
public static void main(String[] args) {
System.out.println(df(3));
}
You're encountering an infinite loop with df(n * df(n - 1));
n * df(n-1) will compute the factorial, and you're inadvertently feeding your answer back into the recursive method, causing it to go on forever
Change
return df(n * df(n - 1));
to
return n * df(n - 1);
and you should get the correct result for factorials
Once you have this working recursive factorial method, it becomes much easier to create a double factorial by just using df(df(3))
I think you should use mutual recursion with the help of factorial.
The general g-factorial function can compose factorial g times:
public static long gf(long n, long g) {
if (g == 1){
return fact(n);
}
return fact(gf(n, g - 1));
}
The specific double factorial can be gf(n, 2):
public static long df(long n) {
return gf(n, 2);
}
And the factorial helper function:
public static long fact(long n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
Now test:
public static void main(String[] args) {
System.out.println(df(3));
}
We can do:
public static long factorial(long n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
public static long twice_factorial(long n) {
return factorial(factorial(n));
}
And, if needed, with some trickery turn this into a single method:
public static long twice_factorial(long n) {
return new Object() {
long factorial(long n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
long twice_factorial(long n) {
return factorial(factorial(n));
}
}.twice_factorial(n);
}
But this is a useless function as it's only good for n < 4 -- once we reach (4!)!, we exceed the limit of Java's long type:
(4!)! = 24! = 620,448,401,733,239,439,360,000
Java 'long' +max = 9,223,372,036,854,755,807
If you want this function to be useful, you might use a floating approximation equation instead. But calling approximate factorial again on an approximation probably doesn't make much sense. You'd want a floating approximation equation for the nested factorial value itself.
Or, we can switch to BigInteger:
import java.math.BigInteger;
public class Test {
public static BigInteger factorial(BigInteger n) {
return (n.compareTo(BigInteger.ONE) <= 0) ? n : n.multiply(factorial(n.subtract(BigInteger.ONE)));
}
public static BigInteger twice_factorial(BigInteger n) {
return factorial(factorial(n));
}
public static void main(String[] args) {
System.out.println(twice_factorial(new BigInteger(args[0])));
}
}
USAGE
> java Test 4
620448401733239439360000
>
But this only gets to (7!)! before we get java.lang.StackOverflowError! If we want to go further, we need to dump the recursion and compute the factorial iteratively:
public static BigInteger factorial(BigInteger n) {
BigInteger result = BigInteger.ONE;
while (n.compareTo(BigInteger.ONE) > 0) {
result = result.multiply(n);
n = n.subtract(BigInteger.ONE);
}
return result;
}
USAGE
> java Test 8
34343594927610057460299569794488787548168370492599954077788679570543951730
56532019908409885347136320062629610912426681208933917127972031183174941649
96595241192401936325236835841309623900814542199431592985678608274776672087
95121782091782285081003034058936009374494731880192149398389083772042074284
01934242037338152135699611399400041646418675870467025785609383107424869450
...
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000
>
Firstly, define your factorial function:
Via Jupyter:
#include <iostream>
std::cout << "some output" << std::endl;
long fac(long n) {
if( n == 1)
return 1;
else
return n * fac((n-1));
}
And after define your function:
long double_fac(long n)
{
long step_one = fac(n);
return fac(step_one);
}
Factorielle-Algorythme

Calculating the product of BigInteger[]

Context: I'm trying to calculate factorials for very large n using the BigInteger class in Java (for n>100,000) and so far this what I'm doing:
Produce all primes less than or equal to n using Sieve of Erasthones
Find to which powers they will be raised.
Raise all the numbers to the respective powers.
Use a divide and conquer recursive method to multiply them all.
From the research I've done on the internet, this is asymptotically faster than simply multiplying all k up to n. However I've noticed that the slowest part of my implementation is the part where I multiply all the prime powers. My questions are:
Is there a faster way to calculate the product of lots of numbers?
Can my implementation be improved ?
Code:
public static BigInteger product(BigInteger[] numbers) {
if (numbers.length == 0)
throw new ArithmeticException("There is nothing to multiply!");
if (numbers.length == 1)
return numbers[0];
if (numbers.length == 2)
return numbers[0].multiply(numbers[1]);
BigInteger[] part1 = new BigInteger[numbers.length / 2];
BigInteger[] part2 = new BigInteger[numbers.length - numbers.length / 2];
System.arraycopy(numbers, 0, part1, 0, numbers.length / 2);
System.arraycopy(numbers, numbers.length / 2, part2, 0, numbers.length - numbers.length / 2);
return product(part1).multiply(product(part2));
}
Note that BigInteger uses the karatsuba algorithm for multiplication.
I know that there are lots of questions about calculating factorials. But mine is about calculating the product of BigIntegers for which there is not much resource. (I've seen someone say "Use Divide and Conquer method", but I don't remember where, and I haven't seen any implementation around.
One way to improve the performance is to do the following:
Sort your array of numbers you need to multiply together
Create two new lists: a and b.
For each number in the input list that you need to multiply, it is likely to appear more than once. Let's say number v_i appears n_i times. Then add v_i to the a n_i / 2 times (rounded down). If n_i is odd, add v_i once to b as well.
To compute the result, do:
BigInteger A = product(a);
BigInteger B = prudoct(b);
return a.multiply(a).multiply(b);
To see how it works, consider your input array is [2, 2, 2, 2, 3, 3, 3]. So, there are four 2s and three 3s. Arrays a and b will correspondingly be
a = [2, 2, 3]
b = [3]
Then you will recursively call to compute the product of these. Note that we reduced the number of numbers that we want to multiply from 7 to 4, almost by a factor of two. The trick here is that for numbers that occur many times, we can compute the product of only half of them, and then raise it to the power of two. Very similar to how the power of a number can be computed in O(log n) time.
I propose another idea, the pow algorithm is very fast, you can compute the all primes with the exponent, like this:
11! -> {2^10, 3^5, 5^2, 7^1, 11^1}
You can compute all primes power , and then use divide and conquer to multiply all of them.
The implementation:
private static BigInteger divideAndConquer(List<BigInteger> primesExp, int min, int max){
BigInteger result = BigInteger.ONE;
if (max - min == 1){
result = primesExp.get(min);
} else if (min < max){
int middle = (max + min)/2;
result = divideAndConquer(primesExp, min, middle).multiply(divideAndConquer(primesExp, middle, max));
}
return result;
}
public static BigInteger factorial(int n) {
// compute pairs: prime, exp
List<Integer> primes = new ArrayList<>();
Map<Integer, Integer> primeTimes = new LinkedHashMap<>();
for (int i = 2; i <= n; i++) {
int sqrt = Math.round((float) Math.sqrt(i));
int value = i;
Iterator<Integer> it = primes.iterator();
int prime = 0;
while (it.hasNext() && prime <= sqrt && value != 0) {
prime = it.next();
int times = 0;
while (value % prime == 0) {
value /= prime;
times++;
}
if (times > 0) {
primeTimes.put(prime, times + primeTimes.get(prime));
}
}
if (value > 1) {
Integer times = primeTimes.get(value);
if (times == null) {
times = 0;
primes.add(value);
}
primeTimes.put(value, times + 1);
}
}
// compute primes power:
List<BigInteger> primePows = new ArrayList<>(primes.size());
for (Entry<Integer,Integer> e: primeTimes.entrySet()) {
primePows.add(new BigInteger(String.valueOf(e.getKey())).pow(e.getValue()));
}
// it multiply all of them:
return divideAndConquer(primePows, 0, primePows.size());
}
Probably the fastest approach :
Sequence.java
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class Sequence {
private final List<BigInteger> elements;
private Sequence(List<BigInteger> elements) {
this.elements = elements;
}
public List<BigInteger> getElements() {
return elements;
}
public int size() {
return elements.size();
}
public Sequence subSequence(int startInclusive, int endExclusive) {
return subSequence(startInclusive, endExclusive, false);
}
public Sequence subSequence(int startInclusive, int endExclusive, boolean sync) {
return Sequence.of(elements.subList(startInclusive, endExclusive), sync);
}
public void addLast(BigInteger element) {
elements.add(element);
}
public BigInteger removeLast() {
return elements.remove(size() - 1);
}
public BigInteger sum() {
return sum(false);
}
public BigInteger sum(boolean parallel) {
return parallel
? elements.parallelStream().reduce(BigInteger.ZERO, BigInteger::add)
: elements.stream().reduce(BigInteger.ZERO, BigInteger::add);
}
public BigInteger product() {
return product(false);
}
public BigInteger product(boolean parallel) {
return parallel
? elements.parallelStream().reduce(BigInteger.ONE, BigInteger::multiply)
: elements.stream().reduce(BigInteger.ONE, BigInteger::multiply);
}
public static Sequence range(int startInclusive, int endExclusive) {
return range(startInclusive, endExclusive, false);
}
public static Sequence range(int startInclusive, int endExclusive, boolean sync) {
if (startInclusive > endExclusive) {
throw new IllegalArgumentException();
}
final List<BigInteger> elements = sync ? Collections.synchronizedList(new ArrayList<>()) : new ArrayList<>();
for (; startInclusive < endExclusive; startInclusive++) {
elements.add(BigInteger.valueOf(startInclusive));
}
return new Sequence(elements);
}
public static Sequence of(List<BigInteger> elements) {
return of(elements, false);
}
public static Sequence of(List<BigInteger> elements, boolean sync) {
return new Sequence(sync ? Collections.synchronizedList(elements) : elements);
}
public static Sequence empty() {
return empty(false);
}
public static Sequence empty(boolean sync) {
return of(new ArrayList<>(), sync);
}
}
FactorialCalculator.java
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
public final class FactorialCalculator {
private static final int CHUNK_SIZE = Runtime.getRuntime().availableProcessors();
public static BigInteger fact(int n) {
return fact(n, false);
}
public static BigInteger fact(int n, boolean parallel) {
if (n < 0) {
throw new IllegalArgumentException();
}
if (n <= 1) {
return BigInteger.ONE;
}
Sequence sequence = Sequence.range(1, n + 1);
if (!parallel) {
return sequence.product();
}
sequence = parallelCalculate(splitSequence(sequence, CHUNK_SIZE * 2));
while (sequence.size() > CHUNK_SIZE) {
sequence = parallelCalculate(splitSequence(sequence, CHUNK_SIZE));
}
return sequence.product(true);
}
private static List<Sequence> splitSequence(Sequence sequence, int chunkSize) {
final int size = sequence.size();
final List<Sequence> subSequences = new LinkedList<>();
int index = 0, targetIndex;
while (index < size) {
targetIndex = Math.min(index + chunkSize, size);
subSequences.add(sequence.subSequence(index, targetIndex, true));
index = targetIndex;
}
return subSequences;
}
private static Sequence parallelCalculate(List<Sequence> sequences) {
final Sequence result = Sequence.empty(true);
sequences.parallelStream().map(s -> s.product(true)).forEach(result::addLast);
return result;
}
}
Test :
public static void main(String[] args) {
// warm up
for (int i = 0; i < 100; i++) {
FactorialCalculator.fact(10000);
}
int n = 1000000;
long start = System.currentTimeMillis();
FactorialCalculator.fact(n, true);
long end = System.currentTimeMillis();
System.out.printf("Execution time = %d ms", end - start);
}
Result :
Execution time = 3066 ms
OS : Win 10 Pro 64-bit
CPU : Intel Core i7-4700HQ # 2.40GHz 2.40GHz

Combinations with BigInteger in java

I am working on an assignment where I have to implement a recursive way to calculate the combination of two numbers. For example, 5C3 would be 10. That is, there are 10 combinations of 3 objects out of 5 total. However, I would like to implement a way to use the BigInteger class so I can calculate larger combinations, such is 2400 pick 3. For some reason, my code still returns a negative number, much like the behavior if it were to be regular integers. I've included my code below. Could someone please tell me where I am going wrong?
import java.math.BigInteger;
public class Combination {
public static BigInteger[][] memo = new BigInteger[3000][3000];
public static BigInteger choose(BigInteger n, BigInteger k) {
if (n.intValue() == 0 && k.intValue() > 0) {
return BigInteger.ZERO;
} else if (k.intValue() == 0 && n.intValue() >= 0) {
return BigInteger.ONE;
} else if (memo[n.intValue()][k.intValue()] != null) {
return memo[n.intValue()][k.intValue()];
} else {
memo[n.intValue()][k.intValue()] = choose(n.subtract(BigInteger.ONE), k.subtract(BigInteger.ONE)).add(choose(n.subtract(BigInteger.ONE), k));
}
return memo[n.intValue()][k.intValue()];
}
public static void main(String args[]) {
if (args.length < 1) {
System.out.println("Usage: java Combination <N> <K>");
System.exit(0);
}
int H = Integer.parseInt(args[0]);
int R = Integer.parseInt(args[1]);
BigInteger N = BigInteger.valueOf(H);
BigInteger K = BigInteger.valueOf(R);
System.out.println(choose(N, K).intValue());
}
}
System.out.println(choose(N, K).intValue());
should be
System.out.println(choose(N, K).toString());

Project Euler 25 infinite loop

I'm working on the Project Euler 25. I worked out how to do Fibonacci and I'm using BigInteger. My program seems to be running for an infinite loop (or so I think). Could it be that it is taking a long time or is it actually going into infinite loop? Can someone point me in the correct direction so I can fix it?
import java.math.BigInteger;
public class Problem25 {
public static void main(String[] args) {
getTerm(0);
}
public static void getTerm(int start) {
BigInteger var = BigInteger.ZERO;
BigInteger var2 = BigInteger.valueOf(start);
int counter = 0;
while(true) {
BigInteger temp = var.add(var2);
var = var2;
var2 = temp;
counter++;
if(var.toString().length() > 1000) {
System.out.print(counter);
}
}
}
}
EDIT: Sorry people. I thought, I had break; but thanks for your responses.
You have no condition for terminating the loop:
while(true) { // << always true ;P
BigInteger temp = var.add(var2);
var = var2;
var2 = temp;
counter++;
if(var.toString().length() > 1000) {
System.out.print(counter);
}
}
So it is an infinite loop. You have two (or even more) options:
Specify in the while(statement) what is the condition to continue with the loop for another round.
Add some break; statement to stop the loop if a certain condition is evaluated as true.
getTerm(0);
Shouldn't this be getTerm(1);?
Also, MByD's answer is right; but this is also a critical problem. Without changing this, your program will never output.
1) Yes, you have an infinite loop. Put a break; statement right after your print().
2) Try looking for the first, oh, two-digit term. Or three-digit. Baby steps are good with a lot of the Project Euler problems.
3) Run it under a debugger, and watch what's happening. Combines well with 2).
You're calling getTerm(0), so initially var and var2 are both zero. Then you add var2 to var which is still zero, etc., so both var and var2 stay zero and you never make any progress. I think you meant getTerm(1), which should correctly generate the Fibonacci sequence.
And of course, you probably want to break out of the loop once you've found the answer.
Why don't you just print every value until a value with 1000 digits is found? There won't be that many anyway because the numbers grow with the golden ration on average.
And as stated elsewhere, add a stopcondition:
if(var.toString().length() > 1000) {
break;
}
Since true is always true, your loop will continue running forever unless you manually terminate it. Use break; for this. With your implementation, I think you should place it right after the line System.out.print(counter)
You can use:
while( !isGood() ) {
...
}
instead of
while(true) {
...
if ( isGood() ) {
break;
}
}
Here are 3 solutions that use the approach above (from slow to fast):
1) Generate all Fibonacci numbers until the condition is satisfied. Count the digits using division by 10. Time: 6625 ms
import java.math.BigInteger;
public class P25 {
final static int N = 1000;
public static void main(String[] args) {
int result = getTheFirstIndexHavingTheSpecifiedNumberOfDigits(N);
System.out.println(result);
}
// similar performance if you use an "aux" variable
private static int getTheFirstIndexHavingTheSpecifiedNumberOfDigits(int n) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
int i = 1;
while ( hasLessThanSpecifiedNumberOfDigits(a, n) ) {
b = b.add(a);
a = b.subtract(a);
i++;
}
return i;
}
private static boolean hasLessThanSpecifiedNumberOfDigits(BigInteger x, int n) {
return getNumberOfDigits(x) < n;
}
private static int getNumberOfDigits(BigInteger x) {
int numberOfDigits = 0 ;
while ( x.compareTo(BigInteger.ZERO) > 0 ) {
numberOfDigits++;
x = x.divide(BigInteger.TEN);
}
return numberOfDigits;
}
}
2) Generate all Fibonacci numbers until the condition is satisfied. Count the digits using the length of the string. Time: 783 ms
import java.math.BigInteger;
public class P25 {
final static int N = 1000;
public static void main(String[] args) {
int result = getTheFirstIndexHavingTheSpecifiedNumberOfDigits(N);
System.out.println(result);
}
private static int getTheFirstIndexHavingTheSpecifiedNumberOfDigits(int n) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
int i = 1;
while ( hasLessThanSpecifiedNumberOfDigits(a, n) ) {
b = b.add(a);
a = b.subtract(a);
i++;
}
return i;
}
private static boolean hasLessThanSpecifiedNumberOfDigits(BigInteger x, int n) {
return getNumberOfDigits(x) < n;
}
private static int getNumberOfDigits(BigInteger x) {
return x.toString().length();
}
}
3) Store the lowest BigInteger that has 1000 digits ( 10^999 ). Generate all Fibonacci numbers and compare them with the computed number. Time: 19 ms
import java.math.BigInteger;
public class P25 {
final static int N = 1000;
final static BigInteger MIN = BigInteger.TEN.pow(N-1);
public static void main(String[] args) {
int result = getTheFirstIndexHavingTheSpecifiedNumberOfDigits(N);
System.out.println(result);
}
private static int getTheFirstIndexHavingTheSpecifiedNumberOfDigits(int n) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
int i = 1;
while ( a.compareTo(MIN) < 0 ) {
b = b.add(a);
a = b.subtract(a);
i++;
}
return i;
}
}

Categories

Resources