Implementing Ackermann Function by Java with BigInteger support - java

I'm getting StackOverflowError (Exception in thread "main" java.lang.StackOverflowError) for the following code. But the program works fine for m=3, n=3 (or other lower values) but does not work for m=4 and n=2 or 3.
public class AckermannFunction
{
static BigInteger One = BigInteger.ONE;
static BigInteger Zero = BigInteger.ZERO;
static BigInteger ackmnFun(BigInteger m, BigInteger n)
{
if (m.equals(Zero))
return n.add(One);
if (n.equals(Zero))
return ackmnFun(m.subtract(One), One);
return ackmnFun(m.subtract(One), ackmnFun(m, n.subtract(One)));
}
public static void main(String[] args)
{
BigInteger m = new BigInteger("4");
BigInteger n = new BigInteger("3");
System.out.println(ackmnFun(m, n));
}
}
There are too many recursive calls I understand. Is there any way to get rid of this error?
Thanks.

Rather than doing this recursively, you could approach it as a dynamic programming problem, and construct a table of values from the bottom up. Then rather than making recursive calls, you simply reference your table to create the next entry.

I've found a solution of my question by myself. I want to share it with you.
Since the Ackermann function calls itself for so many times even for a very low value of m & n, what I did, I added few more terminating condition up to m=3 and n=3 (to minimize recursive calls). And the tricks worked. I found initial values by running the original recursive function and then added all these as terminating condition.
The program finds the Ackermann(4,2) in a few seconds now. The answer is very long containing 19729 decimal digits.

Related

I'm working on Euler 12 , the code i have seems to workes properly but too slow , very very slow. How can i modify it to run faster?

Like i sad , i am working on Euler problem 12 https://projecteuler.net/problem=12 , i believe that this program will give the correct answer but is too slow , i tried to wait it out but even after 9min it still cant finish it. How can i modify it to run faster ?
package highlydivisibletriangularnumber_ep12;
public class HighlyDivisibleTriangularNumber_EP12 {
public static void findTriangular(int triangularNum){
triangularValue = triangularNum * (triangularNum + 1)/2;
}
static long triangularValue = 0l;
public static void main(String[] args) {
long n = 1l;
int counter = 0;
int i = 1;
while(true){
findTriangular(i);
while(n<=triangularValue){
if(triangularValue%n==0){
counter++;
}
n++;
}
if(counter>500){
break;
}else{
counter = 0;
}
n=1;
i++;
}
System.out.println(triangularValue);
}
}
Just two simple tricks:
When x%n == 0, then also x%m == 0 with m = x/n. This way you need to consider only n <= Math.ceil(sqrt(x)), which is a huge speed up. With each divisor smaller than the square root, you get another one for free. Beware of the case of equality. The speed gain is huge.
As your x is a product of two numbers i and i+1, you can generate all its divisors as product of the divisors of i and i+1. What makes it more complicated is the fact that in general, the same product can be created using different factors. Can it happen here? Do you need to generate products or can you just count them? Again, the speed gain is huge.
You could use prime factorization, but I'm sure, these tricks alone are sufficient.
It appears to me that your algorithm is a bit too brute-force, and due to this, will consume an enormous amount of cpu time regardless of how you might rearrange it.
What is needed is an algorithm that implements a formula that calculates at least part of the solution, instead of brute-forcing the whole thing.
If you get stuck, you can use your favorite search engine to find a number of solutions, with varying degrees of efficiency.

Recursive Exponent Method stack overflow

I already searched everywhere for a solution for my problem, but didn't get one. So what I'm trying to do ist use recursion to find out whats a passed integer variable's base to the power of the passed exponent. So for example 3² is 9. My solution really looks like what I found in these forums, but it constantly gives me a stack overflow error. Here is what I have so far.(To make it easier, I tried it with the ints directly not using scanner to test my recursion) Any idea?
public class Power {
public static int exp(int x,int n) {
n = 3;
x = 2;
if (x == 0) {
return 1;
}
else {
return n * exp(n,x-1);
}
}
public static void main(String[] args) {
System.out.println(exp(2,3));
}
}
Well, you've got three problems.
First, inside of the method, you're reassigning x and n. So, regardless of what you pass in, x is always 2, and n is always 3. This is the main cause of your infinite recursion - as far as the method is concerned, those values never update. Remove those assignments from your code.
Next, your base case is incorrect - you want to stop when n == 0. Change your if statement to reflect that.
Third, your recursive step is wrong. You want to call your next method with a reduction to n, not to x. It should read return x * exp(x, n-1); instead.

Need explaination on two different approach to find factorial

I am a beginner.I already learned C. But now Java is seeming difficult to me. As in C programming my approach was simple , when I looked at Book's programs for simple task such as Factorial, its given very complex programs like below -
class Factorial {
// this is a recursive method
int fact(int n) {
int result;
if(n==1) return 1;
result = fact(n-1) * n;
return result;
}
}
class Recursion {
public static void main(String args[]) {
Factorial f = new Factorial();
System.out.println("Factorial of 3 is " + f.fact(3));
System.out.println("Factorial of 4 is " + f.fact(4));
System.out.println("Factorial of 5 is " + f.fact(5));
}
}
Instead, when I made my own program (given below) keeping it simple , it also worked and was easy. Can anyone tell me what's the difference between two ?
public class Simplefacto {
public static void main(String[] args) {
int n = 7;
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
System.out.println("The factorial of 7 is " + result);
}
}
also can anyone tell me what is java EE and java SE ?
The first approach is that of recursion. Which is not always fast and easy. (and usually leads to StackOverflowError, if you are not careful). The second approach is that of a normal for loop. Interstingly, both approaches are valid even in "C".
I think you should not compare Java programs with C programs. Both languages were designed for different reasons.
There are two main differences between those programs:
Program 1 uses recursion
Program 2 uses the imperative approach
Program 1 uses a class where all program logic is encapsuled
Program 2 has all the logic "like the good old C programs" in one method
The first method is Recursive. This means that the method makes calls to itself and the idea behind this is that recursion (when used appropriately) can yield extremely clean code, much like your factorial method. Formatted correctly is should look more like:
private int factorial(int n) {
if(n==1) return n;
return fact(n-1) * n;
}
So that's a factorial calculator in two lines, which is extremely clean and short. The problem is that you can run into problems for large values of n. Namely, the infamous StackOverflowError.
The second method is what is known as iterative. Iterative methods usually involve some form of a loop, and are the other option to recursion. The advantage is that they make quite readable and easy to follow code, even if it is somewhat more verbose and lengthy. This code is more robust and won't fall over for large values of n, unless n! > Integer.MAX_VALUE.
In the first case, you are adding a behavior that can be reused in multiple behaviors or main() while in the second case, you are putting inline code thats not reusable. The other difference is the recursion vs iteration. fact() is based on recursion while the inline code in main() is achieving the same thing using iteration

BigInteger loops and logic not working as planned

so I'm trying to make some code where it basically factors really big numbers. I've tried to translate the code that worked using longs into BigIntegers but the result just returns a lot of 2s and 0s. Here it is.
package primes;
import java.math.BigInteger;
public class Primes {
public static void main(String[] args) {
BigInteger y = new BigInteger("0");
BigInteger count= new BigInteger("2");
BigInteger input = new BigInteger("12321");
BigInteger one = new BigInteger("1");
while(input.compareTo(input)!=1) {
y=input.mod(count);
System.out.println(y);
if(y.compareTo(y)==0) {
input=input.divide(count);
System.out.println(count);
} else if(y.compareTo(y)!=0) {
count.add(one);
}
}
}
}
Alright, I see the problem with the count.add(one); but I am still unsure as to how the compareTo function works. Just for clarifciation with what each of these loops are supposed to do, I'm just going to paste the code of the functioning script that works with longs.
package longprimes;
public class LongPrimes {
public static void main(String[] args) {
long input = 121L;
long count = 2;
long y;
while (input!=1){
y = input%count;
if(y==0){
input = input/count;
System.out.println(count);
}
else if(y!=0){
count++;
}
}
}
}
Seemingly what is happening when I updated the BigInteger code a little bit is that it would factor it but it wouldn't divide input so that it would just keep finding the remainder but in the case that it was 0, it didn't actually divide input to end the loop.
Looks like this is a homework assignment, so I'll just point out a few things:
input.compareTo(input)!=1 is probably not what you intended. Ideally, you want to finish that while loop when input is one. But compareTo will return -1, 0 or 1 if the number on the left is less, equal to, or greater than the other number. Consider what this condition actually returns.
y.compareTo(y)==0 is kind of the same thing. You're comparing a number y with itself. Ideally, you want to compare with zero.
count.add(one) is not really doing anything. Consider what happens when you simply do
1 + 2;
you're computing the result of adding one to count but you're also ignoring the result. You might want to save that result somewhere.

Finding really big power of a number

I am creating a small game for students, and in a place, it has to display the value of 27830457+1
I can call BigInteger's pow() method if the number is not this much big. Since the number is very big, that method is useless. How can I find the HUGE power of this kind of numbers? Please help!
Well in binary it's just 10000...01 with 7830456 zeros.
In decimal, there will be approximately two million digits, which is about 2 megabytes of storage. This is well within the feasibility of BigInteger with a default heap size.
In practice, it even uses exponentiation by squaring to compute it quickly (though not guaranteed by the specifications). However the conversion to a String will take some time since it's a linear time operation.
import java.math.BigInteger;
public class BigPow {
public static void main(String[] args) {
BigInteger result = (new BigInteger("2")).pow(27830457).add(BigInteger.ONE);
System.out.println(result);
}
}
Here's a version which will print out the digits slowly:
import java.math.BigInteger;
public class BigPow {
public static void main(String[] args) {
BigInteger result = (new BigInteger("2")).pow(27830457).add(BigInteger.ONE);
BigInteger powten = BigInteger.TEN.pow(2357202);
while(powten.compareTo(BigInteger.TEN) > 0) {
BigInteger digit = result.divide(powten).mod(BigInteger.TEN);
System.out.print(digit);
powten = powten.divide(BigInteger.TEN);
}
}
}
The first digits are:
27337386390628313557307248857732033008168556429738078791761607160549944954510637855005417718646965163546351365984857761796847950377880836291434244529029919271706271982523405687134334692691344477538489450971091437463160940371624647030064741968436401566711255284353690448270545402444641547030399228243743315193608710148721648879085592699913299745785392609301774185427367430782834290629265859073814466687714408436025809860462926275610087354595992436000187216152954542774991509992374985538879880897902639600451627914923043483436514419544413306391278529303650112773297502090619459167888563274071587848623085880067091968911236296732119252937497152769541579516150659424997041968213122450568364121976474269097910635641227922923398092242409755554115985855831015459204780391470591543281267373716556272259386683864538263922398723602210173800151405332100275913619559563575829498369806957031526077258236305186254269056811134135133350936924294101345294335698866339561918857584229744277901180792029180156485000086528174400878657004645726892816943589969701053158760210512171516969813345080894134663207988962182426459128577282934948790911691329475034324656384238413230485050607666988301932660490870167246016897007835866691705399794247746213819662270451531049826029606671683482160663572103374
Confirmed by WolframAlpha.
I don't know why you think BigInteger isn't up to this:
import java.math.BigInteger;
public class Test {
public static void main(String[] args) throws Exception {
BigInteger big = BigInteger.valueOf(2)
.pow(7830457)
.add(BigInteger.ONE);
System.out.println(big);
}
}
It takes a little while (particularly the string conversion at the end), but it's perfectly reasonable.
As Peter noted, shifting ONE left 7830457 is much neater, mind you. I'd argue it's a bit less clear - and of course it doesn't help in the string conversion part.
EDIT: Almost all of the time is spent in the string conversion. It finished in the end on my box though. I can't see the start of it any more, but it ends with...
08570502260645006898157834607641626568029302766491883299164453304032280181734737
79366998940913082443120328458954436211937775477966920836932628607888755839700303
873
You should be able to calculate this with BigInteger.
System.out.println(BigInteger.ONE.shiftLeft(7830457).add(BigInteger.ONE));
Try something like this:
BigInteger mant = new BigInteger("2");
BigInteger result = mant.pow(7830457).add(BigInteger.ONE);

Categories