Can the standard Ackermann be optimized? - java

The standard Ackermann formula as written in Java:
public static int ack(int x, int y) {
if (x == 0) {
return y + 1;
} else if (y == 0) {
return ack(x-1, 1);
} else {
// perforce (x > 0) && (y > 0)
return ack(x-1, ack(x,y-1));
}
}
I've been wondering - is there a faster version to implement this? I'm thinking maybe there is by using an accumulator or a loop.

Yes, for example by "cheating". If m is 5 or higher, none of the results can be represented by an int. For m = 4, only the n < 2 cases can be represented. For m < 4, there are simple closed formula's based on n.
Everything else would overflow anyway, so let's pretend those cases don't even happen (or you could throw an error or whatever).
Not tested:
int Ackerman(int m, int n) {
switch (m) {
case 0:
return n + 1;
case 1:
return n + 2;
case 2:
return n * 2 + 3;
case 3:
return (int)((1L << (n + 3)) - 3);
case 4:
return n == 0 ? 13 : 65533;
}
}

I can tell you one thing... int will not suffice for very many values of x and y
If you're going to be calling the function repetitively, you can create a int[][] array to store various values so you can look them up the second+ time around and only need to compute it once. But as for speeding up a single execution... not sure.

This variation is faster:
public static int ack(int x, int y) {
while (x != 0) {
y = y == 0 ? 1 : ack(x, y - 1);
x--;
}
return y + 1;
}

Related

How to find the number of multiplications for x^63 using the exponent recursive function and how to justify it?

How would I go about justifying this algorithm is O(log n)?
public static long exponentiation(long x, int n){
if(n == 0){
return 1;
}
else if (n % 2 == 0){
x = exponentiation(x, n / 2);
return x * x;
}
else{
return x * exponentiation(x, n-1);
}
}
Each recursive call to method exponentiation is a multiplication step. Hence you need to count the number of recursive calls. There are several ways to achieve this. I chose to add another parameter to the method.
public static long exponentiation(long x, int n, int count) {
if (n == 0) {
System.out.println("steps = " + count);
return 1;
}
else if (n % 2 == 0) {
x = exponentiation(x, n / 2, count + 1);
return x * x;
}
else {
return x * exponentiation(x, n - 1, count + 1);
}
}
Here is the initial call to method exponentiation
exponentiation(2, 63, 0);
When I run the above code, the following is printed
steps = 11
You can use a static counter as well (without changing the prototype of the function):
public static long counter = 0;
public static long exponentiation(long x, int n){
if(n == 0){
return 1;
}
else if (n % 2 == 0){
x = exponentiation(x, n / 2);
counter++;
return x * x;
}
else{
counter++;
return x * exponentiation(x, n-1);
}
}
However, you need to reset the counter before calling the function each time, i.e., set counter = 0.
Theoretical Analysis
Note that you need to the counter to prove that it is in O(log(n)). To prove the complexity, just you need to find the complexity term by looking at the flow of the code. Suppose T(n) is the number of multiplications for computing x^n. So, based on the written code, T(n) = T(n/2) + 1, if n is even, and T(n) = T(n-1) + 1, if n is odd. Now, at least in one of two consecutive recursions, input n is even. Therefore, at most 2 log(n) is required to reach to n = 0. Because, for each even input, the next input will be halved. So, we can conclude that the algorithm is in O(log(n)).

binary search divide by 4

Binary search divide array in 2 parts. But what if I want to divide the array in 4 parts ?
Here is my approach
while (low <= h){
quartal = (low + high) / 4;
if (array[quartal] == x) return quartal;
if (array[2*quartal] == x) return 2*quartal;
if (array[3*quartal] == x) return 3*quartal;
if (array[4*quartal] == x) return 4*quartal;
if (array[quartal] > x) high = quartal-1;
if (array[quartal] < x && array[2*quartal] > x){
low = quartal + 1;
high = 2*quartal-1;
}
if (array[2*quartal] < x && array[3*quartal] > x){
low = quartal + 1;
high = 2*quartal -1;
}
if (array[3*quartal] < x && array[4*quartal] > x){
low = 2*quartal + 1;
high = 3*quartal -1;
}
if (array[4*quartal] < x){
low = 3*quartal + 1;
}
that work but not for all values.
can someone tell me what wrong with my approach?
To answer your question:
Is your array sorted? Binary search only works on sorted arrays.
In the last if-statement, you check if array[4*quartal] < x. Note that this can lead to errors, as quartal is an integer, and therefore 4*quartal will not be equal to (low + high) but rather 4*floor((low+high)/4). Therefore, you may be dividing into 5 segments instead of 5 depending on if (low+heigh) is multiple of 4.
Because 4*quartal should be the end of the segment in your array which you are searching in, I would suggest replacing 4*quartal by (low+high).
I hope this does help.
In addition to what CodingTil has said.
You will have to do the following when doing your checks. Try to think of what would happen with edge cases like a length of 103 or just an array of [0,1]. In your code if we had an array length of 103, we would divide by 4 and get quartels of length 25.75. This can be problematic if we floor the quartel at the start as you'll miss out on values at index 101 and above. You'll have to adjust your other if statements in a similar manner.
if (array[floor(quartal)] == x) return floor(quartal);
if (array[floor(2*quartal)] == x) return floor(2*quartal);
if (array[floor(3*quartal)] == x) return floor(3*quartal);
if (array[high] == x) return high; // should be a whole number so no need to round
Your seventh if statement has an error (your eighth if statement will also have to be adjusted), it should read as follows. And I believe you'll be able to get rid of the ninth if statement altogether.
if (array[floor(2*quartal)] < x && array[floor(3*quartal)] > x){
low = floor(2*quartal) + 1;
high = floor(3*quartal) -1;
}
// high remains unchanged, as we are in the highest quartal
if (array[floor(3*quartal)] < x && array[floor(4*quartal)] > x){
low = floor(3*quartal) + 1;
}

Calculating how far a robot will move in Java

I'm working on a project for school that requires me to move a robot. How far the robot will move each second (variable t) is calculated by the function below.
The first function is easy. The 2nd and 3rd on the other are where I'm stuck. How would I write F(t-1)? Below is what I have so far.
if (t == 0) {
distance = 2;
} else if (t > 0 && <=6 || t > 12) {
// No clue on how to write the 2nd distance equation.
} else if (t >= 7 && <=12) {
// No clue on how to write the 3rd distance equation.
}
Recursion really isn't necessary to solve this.
Note that in each of the non-zero time cases, F(t) = F(t-1) + something.
So you can simply do:
double f = 2; /* Initial value at t=0 */
for (int t = 1; t <= maxT; ++t) { // maxT is the maximum value of t.
if (t <= 6 || t > 12) {
f += /* something for case 2 */;
} else {
f += /* something for case 3 */;
}
}
System.out.println(f);
You can do this with recursion, but you will get a StackOverflowError if maxT becomes modestly large; by contrast, using a loop will work for arbitrarily large maxT (modulo floating point errors).
As pointed out by #Andreas, you can do this without looping over all values of t:
double f = 2 * (maxT + 1);
for (int t = 7; t <= maxT && t <= 12; ++t) {
f += log(t) - 2;
}
and you can eliminate that loop too by precomputing the values.
This is a problem which involves the use of recursion. By and large, pay close attention to the notation Ft-1, since that refers to an evaluation of the specific function at t-1.
I won't write out all of the code, but I'll give you some of the basics:
When t = 0, return 2. This is your base case.
When t is between 0 and 6 inclusive or greater than 12, return an evaluation of the function at t-1 and add 2.
When t is between 7 and 12 both inclusive, return an evaluation of the function at t-1 and add log2(t).
Here's something to get you at least started in the right direction.
public double evaluateDistance(int t) {
if(t == 0) {
return 2;
} else if(t > 0 && t <= 6) || (t > 12) {
// Think about this - it would involve another call to evaluateDistance, but what is t again?
} else if(t >= 7 && t <= 12) {
// Another evaluation involving the function.
// For free, the change of base operation you'll need to get base-2 evaluation for the log:
return ??? + Math.log(t)/Math.log(2);
}
}
Think I figured it out. Sorry if I wasn't clear on what I needed, just needed to figure out how to write the equations in the function. Think I figured it out though.
public double move()
{
int t = 0;
if(t == 0) // After the first second, robot moves 2
{
distance = 2;
}
else if(t > 0 && t <= 6 || t > 12) // From seconds 0 to 6 and after 12, robot moves distance equation
{
distance = (2*t)+2;
}
else if(t >= 7 && t <= 12) // From seconds 7 to 12, robot moves distances equation
{
distance = (2*t)+(Math.log(t)/Math.log(2));
}
position = position + distance;
return position;
}
}

Recursive method for x^n optimised for when n is even

I need to write a recursive method using Java called power that takes a double x and an integer n and that returns x^n. Here is what I have so far.
public static double power(double x, int n) {
if (n == 0)
return 1;
if (n == 1)
return x;
else
return x * (power(x, n-1));
}
This code works as expected. However, I am trying to go the extra mile and perform the following optional exercise:
"Optional challenge: you can make this method more efficient, when n is even, using x^n = (x^(n/2))^2."
I am not sure how to implement that last formula when n is even. I do not think I can use recursion for that. I have tried to implement the following, but it also does not work because I cannot take a double to the power of an int.
if (n%2 == 0)
return (x^(n/2))^2;
Can somebody point me in the right direction? I feel like I am missing something obvious. All help appreciated.
It's exactly the same principle as for x^n == x*(x^(n-1)): Insert your recursive function for x^(n/2) and (...)^2, but make sure you don't enter an infinite recursion for n == 2 (as 2 is even, too):
if (n % 2 == 0 && n > 2)
return power(power(x, n / 2), 2);
}
Alternatively, you could just use an intermediate variable:
if (n % 2 == 0) {
double s = power(x, n / 2);
return s * s;
}
I'd probably just handle 2 as a special case, too -- and avoid the "and"-condition and extra variable:
public static double power(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
if (n == 2) return x * x;
if (n % 2 == 0) return power(power(x, n / 2), 2);
return x * (power(x, n - 1));
}
P.S. I think this should work, too :)
public static double power(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
if (n == 2) return x * x;
return power(x, n % 2) * power(power(x, n / 2), 2);
}
When n is even, the formula is exactly what you wrote: divide n by two, call power recursively, and square the result.
When n is odd, the formula is a little more complex: subtract 1 from n, make a recursive call for n/2, square the result, and multiply by x.
if (n%2 == 0)
return (x^(n/2))^2;
else
return x*(x^(n/2))^2;
n/2 truncates the result, so subtraction of 1 is not done explicitly. Here is an implementation in Java:
public static double power(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
double pHalf = power(x, n/2);
if (n%2 == 0) {
return pHalf*pHalf;
} else {
return x*pHalf*pHalf;
}
}
Demo.
Hint: The ^ operation won't perform exponentiation in Java, but the function you wrote, power will.
Also, don't forget squaring a number is the same as just multiplying it by itself. No function call needed.
Making a small change to your function, it will reduce the number of recursive calls made:
public static double power(double x, int n) {
if (n == 0) {
return 1;
}
if (n == 1) {
return x;
}
if (n % 2 == 0) {
double temp = power(x, n / 2);
return temp * temp;
} else {
return x * (power(x, n - 1));
}
}
Since
x^(2n) = (x^n)^2
you can add this rule to your method, either using the power function you wrote, as Stefan Haustein suggested, or using the regular multiplication operator, since it seems you are allowed to do that.
Note that there is no need for both the base cases n=1 and n=0, one of them suffices (prefferably use the base case n=0, since otherwise your method would not be defined for n=0).
public static double power(double x, int n) {
if (n == 0)
return 1;
else if (n % 2 == 0)
double val = power(x, n/2);
return val * val;
else
return x * (power(x, n-1));
}
There is no need to check that n>2 in any of the cases.
This just reminds me more optimisation could be done
and this following code.
class Solution:
# #param x, a float
# #param n, a integer
# #return a float
def pow(self, x, n):
if n<0:
return 1.0/self.pow(x,-n)
elif n==0:
return 1.0
elif n==1:
return x
else:
m = n & (-n)
if( m==n ):
r1 = self.pow(x,n>>1)
return r1*r1
else:
return self.pow(x,m)*self.pow(x,n-m)
what is more intermediate result could be memorised and avoid redundant computation.

Recursion and multiplication

Is this possible guys? This is homework I have, and my teacher obviously believes it is, but it seems to me that it's impossible not to use addition or multiplication outside of the short-multiplication method.
Write (and provide a tester for) a recursive algorithm:
int multiply(int x, int y)
to multiply two positive integers together without using the *
operator. Do not just add x to itself y times!!!
(Hint: Write a recursive method that will multiply an integer by a
value in the range 0 .. 10. Then write a second recursive method to
implement the multiplication algorithm you learned to multiply
multi-digit numbers in elementary school.)
My issue is that once you break down any multi digit number and starting adding those together you have to use multiplication of numbers greater than 10, i.e 22 * 6 is 2 * 6 + 20 * 6 ... so am I totally missing something?
EDIT
I guess I should have added this is the code I have,
public int mult(int x, int y){
return x == 0 ? 0 : (mult(x-1, y) + y);
}
which is perfect, but as far as I understand the instructions, that's breaking do not just add x to itself y times. I personally believe it isn't, but my teacher hasn't been very clear, and I'd like to know if there's some other way that I havn't thought of, sorry for the confusion.
Yes, it's possible. Yes, I think you're missing something. Try writing down the steps you'd follow to manually multiply two numbers, the way you learned in elementary school.
Then turn those steps into code.
My interpretation of the assignment is that the teacher would like the student to implement a recursive algorithm to perform Grid method multiplication (the kind we learn in elementary school).
For example, multiplying 34 x 13 would be done like so...
34
* 13
====
12
90
40
+300
====
442
I didn't have easy access to a Java development environment, so I wrote the code in C# but the algorithm should be simple enough to convert into Java.
public int Multiply(int x, int y)
{
if (x < 0) throw new ArgumentException("must be positive integer", "x");
if (y < 0) throw new ArgumentException("must be positive integer", "y");
if (x == 0 || y == 0) return 0; // obvious quick-exit condition
// integer division
int xDivBy10 = x / 10;
int yDivBy10 = y / 10;
bool xIsSingleDigit = xDivBy10 == 0;
bool yIsSingleDigit = yDivBy10 == 0;
// base case
if (xIsSingleDigit && yIsSingleDigit)
{
return MultiplySingleDigits(x, y);
}
// otherwise, use grid multiplication recursively
// http://en.wikipedia.org/wiki/Grid_method_multiplication
if (xIsSingleDigit) // y must not be a single digit
{
return (Multiply(x, yDivBy10) * 10) + Multiply(x, y % 10);
}
if (yIsSingleDigit) // x must not be a single digit
{
return (Multiply(xDivBy10, y) * 10) + Multiply(x % 10, y);
}
// else - x and y are both numbers which are not single digits
return (Multiply(x, yDivBy10) * 10) + Multiply(x, y % 10); // the same code as the "if (xIsSingleDigit)" case
}
// technically, this algorith can multiply any positive integers
// but I have restricted it to only single digits as per the assignment's requirements/hint
private int MultiplySingleDigits(int x, int y)
{
if (x < 0 || x > 9) throw new ArgumentException("must be in range 0 - 9 (inclusive)", "x");
if (y < 0 || y > 9) throw new ArgumentException("must be in range 0 - 9 (inclusive)", "y");
if (x == 0 || y == 0) return 0; // base case
return x + MultiplySingleDigits(x, y - 1);
}
NOTES:
This approach still uses the * operator but not for actually multiplying x and y, it is used to increase other sub-products by multiples of 10
Many parts of this code could be simplified/refactored but I specifically left them expanded to make the steps more obvious
Of course you can do it.
First of all, think about the condition. If some number is 0, then the result is? Right.. zero.
So.. You'll have if x is zero or y is zero return 0
Now.. saying X * Y is like saying "X, Y times", which is like writing: X + .... + X (Y times).
So, you'll have something like:
x + multiply(x, y - 1);
You'll have to consider the case in which one of the numbers is negative (But if you understand the basic, I believe you can easily do it).
This solution will work for both when y>=0 and y<0
public int multiply(final int x, final int y) {
if (y != 0 && x != 0) {
if (y > 0) {
return multiply(x, y - 1) + x;
} else {
return multiply(x, y + 1) - x;
}
}
return 0;
}
Easily possible.
int multiply(int x, int y) {
if(y == 0) {
return 0;
}
return x + multiply(x, y - 1);
}
The above fails to take into account the case where y is negative, but you wouldn't want me to do all your work for you . . .
static int Multiply(int x, int y)
{
if (y > 0 && x > 0)
return (x + Multiply(x, y - 1));
if (y < 0 && x > 0)
return -Multiply(x, -y);
if (x < 0 && y > 0)
return -Multiply(-x, y);
if (x < 0 && y < 0)
return Multiply(-x, -y);
return 0;
}

Categories

Resources