Performance of MutableBigInteger

2019-06-01 00:53发布

问题:

I tried calculating the sum of the digits of square root of integers below a particular input with large precison (upto 10000) using BigInteger.

public class SquareRootHackerRankJarvis {
static BigInteger limit;
static BigInteger a;
static BigInteger b;

private static BigInteger squareroot(int n, BigInteger ten,
        BigInteger hundred, BigInteger five) {
    a = BigInteger.valueOf(n * 5);
    b = BigInteger.valueOf(5);

    while (b.compareTo(limit) == -1) {
        if (a.compareTo(b) != -1) {
            a = a.subtract(b);
            b = b.add(ten);
        } else {
            a = a.multiply(hundred);
            b = (b.divide(ten)).multiply(hundred).add(five);
        }
    }

    return b.divide(hundred);
}

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int N = scanner.nextInt();
    int P = scanner.nextInt();
    int sum = 0;
    int p = 1;
    BigInteger ten = BigInteger.valueOf(10);
    BigInteger hundred = BigInteger.valueOf(100);
    BigInteger five = BigInteger.valueOf(5);
    limit = ten.pow(P + 1);
    for (int i = 1; i <= N; i++) {
        if (p * p == i) {
            p++;
            continue;
        }
        BigInteger x = squareroot(i, ten, hundred, five);

        char[] digits = x.toString().toCharArray();

        for (int j = 0; j <= P - 1; j++) {
            sum += Character.getNumericValue(digits[j]);
        }
    }
    System.out.println(sum);
    scanner.close();
}}

The performance was quite bad and it eats a lot of time for precision 10000 (P). I read in another post that MutableBigInteger performs well ahead of BigInteger, since it is mutable.Therefore I refactored the code using MutableBigInteger.

public class SquareRootHackerRankJarvisMutableBigInteger {

static Object limit;
static Object a;
static Object b;

public static void main(String[] args) throws NoSuchMethodException,
        SecurityException, InstantiationException, IllegalAccessException,
        IllegalArgumentException, InvocationTargetException,
        ClassNotFoundException {
    Scanner scanner = new Scanner(System.in);
    int N = scanner.nextInt();
    int P = scanner.nextInt();
    int sum = 0;
    int p = 1;
    BigInteger tenB = BigInteger.valueOf(10);
    Class<?> c = Class.forName("java.math.MutableBigInteger");
    Constructor<?> constructor = c.getDeclaredConstructor(int.class);
    constructor.setAccessible(true);
    Constructor<?> constructor1 = c
            .getDeclaredConstructor(BigInteger.class);
    constructor1.setAccessible(true);

    Method add = c.getDeclaredMethod("add", new Class[] { c });
    Method subtract = c.getDeclaredMethod("subtract", new Class[] { c });
    Method mul = c.getDeclaredMethod("mul", new Class[] { int.class, c });
    Method divide = c.getDeclaredMethod("divide", new Class[] { long.class,
            c });
    Method compare = c.getDeclaredMethod("compare", new Class[] { c });
    Method copyValue = c.getDeclaredMethod("copyValue", new Class[] { c });
    add.setAccessible(true);
    subtract.setAccessible(true);
    mul.setAccessible(true);
    divide.setAccessible(true);
    compare.setAccessible(true);
    copyValue.setAccessible(true);

    Object ten = constructor.newInstance(10);
    Object five = constructor.newInstance(5);
    Object v = constructor.newInstance(0);
    Object sqrt = constructor.newInstance(0);
    limit = constructor1.newInstance(tenB.pow(P + 1));
    for (int i = 1; i <= N; i++) {
        if (p * p == i) {
            p++;
            continue;
        }
        a = constructor.newInstance(i * 5);
        b = constructor.newInstance(5);

        while (((Integer) compare.invoke(b, limit)).intValue() == -1) {
            if (((Integer) compare.invoke(a, b)).intValue() != -1) {
                subtract.invoke(a, b);
                add.invoke(b, ten);
            } else {
                mul.invoke(a, 100, v);
                copyValue.invoke(a, v);
                divide.invoke(b, 10, v);
                mul.invoke(v, 100, b);
                add.invoke(b, five);
            }
        }

        divide.invoke(b, 100, sqrt);

        char[] digits = sqrt.toString().toCharArray();

        for (int j = 0; j <= P - 1; j++) {
            sum += Character.getNumericValue(digits[j]);
        }
    }
    System.out.println(sum);
    scanner.close();
}}

But still i could not see any performance improvement.Can anyone please give me any suggestions about the proper usage of MutableBigInteger with Reflection?