Reputation: 79
I have this Java code for computing some numbers
import java.math.BigInteger;
class Challenge {
final static BigInteger THOUSAND = new BigInteger("1000");
private static BigInteger compute(long n) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
for (long i = 0; i < n; i++) {
BigInteger next = b.multiply(b).add(a);
a = b;
b = next;
}
return b.mod(THOUSAND);
}
public static void main(String args[]) {
for (long n : new long[] { 1L, 2L, 5L, 10L, 20L, Long.MAX_VALUE }) {
System.out.print(n + " ---> ");
System.out.println(compute(n));
}
}
}
The code iterates several times according to given long numbers (1, 2, 5, etc), starting with a=1
and b=1
:
next = (b*b)+a
a = b
b = next
It then returns b mod 1000
, which it gives the last 3 digits of the calculation.
So far the codes returns:
1 ---> 2
2 ---> 5
5 ---> 783
10 ---> 968
20 ---> 351
9223372036854775807 --->
On the last one the code keeps working but the number if iterations is so big it takes forever so it never finishes.
Is there a way to do this kind of calculations faster, or to get the desired value (mod 1000 of the calculation done that many times) in a better way?
Upvotes: 2
Views: 2466
Reputation: 533510
It would be a lot faster if you use an int
for your calculations. However you will get a better speed up from realising that in each iteration there is only 1,000,000 possible starting values for a
and b
which means the longest possible sequence of values and results for a
and b
without repeating is one million. i.e. you can n % 1,000,000
Most likely there is a shorter repeating sequences.
The reason I say only the lower three digits of a
and b
matter is that you mod 1000
the result, so not matter what the upper digits of a
and b
are they are ignored so all you care about are the values 0
to 999
You can memorizes all possible results starting at 1,1 and it will just be a lookup.
private static long compute(long n) {
int a = 1;
int b = 1;
for (int i = 0, max = (int) (n % 1000000); i < max; i++) {
int next = b * b + a;
a = b;
b = next % 1000;
}
return b % 1000;
}
Upvotes: 5
Reputation: 137084
Yes, keep the running moludo for each calculation. You don't need to calculate all the digits since you are only interested in the last 3 ones.
A first improvement is to have the following:
private static BigInteger compute(long n) {
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
for (long i = 0; i < n; i++) {
BigInteger next = b.multiply(b).add(a);
a = b;
b = next.mod(THOUSAND); // <-- only keep the modulo each time so as not calculate all digits
}
return b.mod(THOUSAND);
}
By doing this, you can realize that you don't need BigInteger
to begin with. The numbers concerned become of value low enough that they hold into a primitive datatype. As such, use a long
(or even an int
): it will be a lot more performant since you don't have the overhead of using a BigInteger
.
private static long compute(long n) {
int a = 1;
int b = 1;
for (long i = 0; i < n; i++) {
int next = b*b + a;
a = b;
b = next % 1000;
}
return b % 1000;
}
Note that this code still won't give you the result for 9223372036854775807
as input. It is simply not possible to loop 9223372036854775807
times. However, this produces the correct result for 100 million in under 5 seconds on my old machine.
Upvotes: 4
Reputation: 1
The number is to big. It's normal to take so long to process this function. You can try to check using this:
long startTime = System.currentTimeMillis();
.....your program....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println(totalTime);
the estimate time to finish it.
Upvotes: -3