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

Java 计算平方根时使用BigInteger的性能改进,java,algorithm,biginteger,bigdecimal,square-root,Java,Algorithm,Biginteger,Bigdecimal,Square Root,我试图计算100以下所有整数的平方根,精度高达10000位。我已经试过用牛顿的方法计算大十进制数了,它占用了很多时间 所以现在我用biginger来求平方根(我认为这个方法涉及的计算量更少,并且不需要维护十进制数字)。即使这样,我的代码也会花费很多时间 public class SquareRootHackerRankJarvis { static BigInteger limit; static BigInteger a; static BigInteger b; private stati

我试图计算100以下所有整数的平方根,精度高达10000位。我已经试过用牛顿的方法计算大十进制数了,它占用了很多时间

所以现在我用biginger来求平方根(我认为这个方法涉及的计算量更少,并且不需要维护十进制数字)。即使这样,我的代码也会花费很多时间

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();
}}
公共类SquareRootHackerRankJarvis{
静态大整数极限;
静态大整数a;
静态大整数b;
私有静态BigInteger平方根(整数n,整数位数,BigInteger十,
大整数一百,大整数五){
限值=10.pow(位数+1);
a=BigInteger.valueOf(n*5);
b=大整数。值为(5);
而(b.compareTo(limit)=-1){
如果(a.与(b)!=-1相比){
a=a.减去(b);
b=b.加(十);
}否则{
a=a.乘(百);
b=(b.除(十))。乘(百)。加(五);
}
}
返回b.除以(百);
}
公共静态void main(字符串[]args){
扫描仪=新的扫描仪(System.in);
int N=scanner.nextInt();
int P=scanner.nextInt();
整数和=0;
int p=1;
BigInteger十=BigInteger.valueOf(10);
BigInteger百=BigInteger.valueOf(100);
BigInteger五=BigInteger.valueOf(5);
对于(int i=1;i
应移到函数
平方根
之外,这样就不会在每次调用函数时创建和初始化它们。请确保它们在此函数中仍然可以访问

BigInteger num;
BigInteger limit;
BigInteger a;
BigInteger b;
应该在函数外部创建,并且应该仅在每次函数调用时初始化

也跟着行

b = (b.divide(ten)).multiply(hundred).add(five);
可以优化为

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

除了快速计算非平方根的无数位数之外,还有一个观察结果是,从2到100,只有25个非复合数

接下来,除了像建议的那样引入常数外,将“在后面的
5
之前引入
0
”减少为两个操作:

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);
}

Jarvis方法(似乎还有您的代码)计算整数的平方根,而不是像你所说的无理数的平方根。显示的代码非常类似。拉出
num
limit
a
b
,然后在调用时重新初始化它们不会使代码线程安全他可以使用
私有静态同步BigInteger square根(整数n,整数位数)
在下面的步骤中处理这个问题
b=(b.除(十))。乘(百)。加(五);
,我试图在最后一位数字前插入一个零。我认为你给出的方法无法实现这一点。我已经包含了我的全部代码。请查看编辑后的问题。当输入为100(N)和100000(P)时,仍然需要很多时间。还有其他建议吗?
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);
}