计算平方根时使用BigInteger的性能改进

时间:2015-06-10 13:34:03

标签: java algorithm biginteger bigdecimal square-root

我试图计算100以下所有整数的平方根,其精度高达10000位。我已经尝试使用Newton的Big Decimal方法,它吃了很多时间。

所以现在使用Jarvis method来使用BigInteger查找平方根。(我认为这种方法涉及的计算次数较少,并且不需要维护十进制数字)。即使这样,我的代码也需要花费很多时间。下面的代码描述了计算。

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

private static BigInteger squareroot(int n, int digits, BigInteger ten,
        BigInteger hundred, BigInteger five) {
    limit = ten.pow(digits + 1);
    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);
    for (int i = 1; i <= N; i++) {
        if (p * p == i) {
            p++;
            continue;
        }
        BigInteger x = squareroot(i, P, 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();
}}

任何人都可以提供或建议正确使用BigInteger以获得最佳性能吗?

对于改进上述算法的评论也很受欢迎。

2 个答案:

答案 0 :(得分:0)

BigInteger ten = BigInteger.valueOf(10);
BigInteger hundred = BigInteger.valueOf(100);
BigInteger five = BigInteger.valueOf(5);

应移到函数squareroot之外,以便每次调用函数时都不会创建和初始化它们。确保在此功能中仍可访问它们。

BigInteger num;
BigInteger limit;
BigInteger a;
BigInteger b;

应该在函数之外创建,并且只应在每次函数调用时初始化。

也在行

之后
b = (b.divide(ten)).multiply(hundred).add(five);

可以优化到

b = b.multiply(ten).add(five);

答案 1 :(得分:0)

除了快速计算非正方形根的多个数字之外的一个观察是,从2到100只有25个非复合数。

接下来,除了引入建议的Maciej之类的常量之外,在尾随0&#34;之前减少5的引入。两个操作:

static final BigInteger
    ten        = BigInteger.TEN,
    oneHundred = BigInteger.valueOf(100),
    five       = BigInteger.valueOf(  5),
    fourtyFive = BigInteger.valueOf( 45);

/** Computes <code>digits</code> decimal digits of <code>n</code>
 * <em>ignoring</em> (decimal) scaling. */
private static BigInteger sqrtDigitsJarvis(int n, int digits) {
    BigInteger
        limit = ten.pow(digits + 1),     // might be an instance data member
        a = BigInteger.valueOf(n*5L),    // la*100), 
        b = five; // BigInteger.valueOf(ib*10 - 45);
// flawed for limit < sqrt(5n)
    while (b.compareTo(limit) < 0) {
        if (0 <= a.compareTo(b)) { // each branch can be parallelised
            a = a.subtract(b);
            b = b.add(ten);
        } else {
            a = a.multiply(oneHundred);
            b = b.multiply(ten).subtract(fourtyFive);
        }
    }
    return b.divide(oneHundred);
}