简体   繁体   中英

Big numbers calculations in Java?

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?

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. ie 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;
}

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM