执行时间:Boost Multi-precision与Java BigInteger

时间:2019-07-18 15:15:58

标签: java c++ boost primes biginteger

我正在尝试实施Lucas-Lehmer素数测试。

我有两种实现,一种是C ++,另一种是Java,如下:

C ++:

int p = 86243;
cpp_int M;

bit_set(M, p);
M = M-1; // M = 2^p - 1;

cpp_int S;
S = 4;

while(p>2) {
         S = pow(S, 2);
         S -= 2;

         S %= M;
         p--;         
}

Java:

int p = 86243;

BigInteger M = BigInteger.ZERO;
BigInteger Two = BigInteger.valueOf(2L);

M = M.setBit(p);
M = M.subtract(BigInteger.ONE); // M = 2^p - 1;

BigInteger S = BigInteger.valueOf(4L);

while(p>2) {
         S = S.pow(2).subtract(Two).mod(M);
         p--;        
}

Java代码的运行速度比C ++代码快得多,对于C ++,我正在使用CodeBlocks和Eclipse for Java。

任何原因吗?我是否特别缺少C ++代码中的任何内容? 任何建议将不胜感激。

2 个答案:

答案 0 :(得分:4)

您可以使用内置的时钟功能检查比较。这是此C ++和Java代码的比较

C ++-> https://ideone.com/oj07xQ

Java-> https://ideone.com/MsAgil

您可以看到C ++花费了1193.19毫秒,而Java花费了2257.244454毫秒

您无法在CodeBlocks和Eclipse等不同的IDE上比较速度

#include<bits/stdc++.h>
#include <boost/multiprecision/cpp_int.hpp>
using boost::multiprecision::cpp_int;
using namespace std;

int32_t main() {
    int start = clock();
    int p = 8624;
    cpp_int M;
    bit_set(M, p);
    M = M-1; // M = 2^p - 1;
    cpp_int S;
    S = 4;
    while(p>2) {
             S = pow(S, 2);
             S -= 2;

             S %= M;
             p--;         
    }
    // cout << S << endl;
    int end = clock();
    cout << "time: " << (end - start)/(double)(CLOCKS_PER_SEC)*1000 << " milliseconds\n";
}
import java.util.*;
import java.lang.*;
import java.io.*;
import java.math.*;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        long startTime = System.nanoTime();
        int p = 8624;
        BigInteger M = BigInteger.ZERO;
        BigInteger Two = BigInteger.valueOf(2L);

        M = M.setBit(p);
        M = M.subtract(BigInteger.ONE); // M = 2^p - 1;

        BigInteger S = BigInteger.valueOf(4L);

        while(p>2) {
                 S = S.pow(2).subtract(Two).mod(M);
                 p--;        
        }
        // System.out.println(S);
        long endTime = System.nanoTime();
        System.out.println("Took "+(endTime - startTime) + " ns"); 

    }
}

答案 1 :(得分:3)

我认为您不应该期望两个程序(Java和C ++版本)都等效。性能主要取决于所使用的算法,而不是语言。在事件探查器中运行C ++版本表明,鸿沟(即mod)是瓶颈。然后,如果您查看划分的来源(/boost/multiprecision/cpp_int/divide.hpp),您会看到以下注释:

  

非常简单,相当长的脑残。   [...]   请注意,有比这更有效的算法   可用,特别是参见Knuth Vol 2。   四肢的数量通常胜过其他选择   并避免了需要额外存储空间的标准化步骤。

但是Java中的BigInteger实现使用称为Knuth和/或BurnikelZiegler的算法。似乎这些更适合大量使用。如果性能确实很重要,则可以尝试使用gnu多精度库(gmp)。在我的计算机上,gmp版本大约比Java / BigInteger快3倍:

#include <iostream>
#include <gmp.h>
using namespace std;

int main()
{
    int p = 86243;
    mpz_t M;
    mpz_init(M);
    mpz_set_ui(M, 0);
    mpz_setbit(M, p);
    mpz_sub_ui(M, M, 1); // M = 2^p - 1;

    mpz_t S;
    mpz_init(S);
    mpz_set_ui(S, 4);

    while(p > 2) {
        mpz_pow_ui(S, S, 2);
        mpz_sub_ui(S, S, 2);

        mpz_mod(S, S, M);

        p--;
    }
    int r = mpz_get_ui(S);
    cout << "Is mersenne prime: " << (r == 0 ? "yes" : "no") << endl;
    return 0;
}

与-lgmp链接