Java 通过DnC计算阶乘

Java 通过DnC计算阶乘,java,java-7,fork-join,Java,Java 7,Fork Join,我试图通过分治策略实现阶乘函数。我使用ForkJoin框架对每个递归任务进行fork,以加快计算速度。 但我发现它并没有像我预期的那样加速。 在不使用ForkJoin的情况下,计算50000的阶乘需要28秒,而 我使用ForkJoin时花了25秒。 这是不带forkjoin的代码: public static BigInteger factorial(long p, long q) { if (q < p) { return new BigInteger("1");

我试图通过分治策略实现阶乘函数。我使用ForkJoin框架对每个递归任务进行fork,以加快计算速度。 但我发现它并没有像我预期的那样加速。 在不使用ForkJoin的情况下,计算50000的阶乘需要28秒,而 我使用ForkJoin时花了25秒。 这是不带forkjoin的代码:

public static BigInteger factorial(long p, long q) {
    if (q < p) {
        return new BigInteger("1");
    }
    if (p == q) {
        return new BigInteger("" + p);
    }
    BigInteger fact = new BigInteger("1");
    fact = fact.multiply(factorial(p, (p + q) / 2)).multiply(factorial((p + q) / 2 + 1, q));
    return fact;
}
公共静态BigInteger阶乘(长p,长q){
if(q
这是forkJoin的代码:

public class Factorial extends RecursiveTask<BigInteger>{
private long p, q;
public Factorial(long p, long q) {
    this.p = p;
    this.q = q;
}
@Override
public BigInteger compute() {
    if(q < p) {
        return new BigInteger("1");
    } 
    if( p == q) {
        return new BigInteger(""+p);
    }
    Factorial f1 = new Factorial(p, (p+q)/2);
    Factorial f2 = new Factorial((p+q)/2 + 1, q);
    f2.fork();
    return f1.compute().multiply(f2.join());        
}    
}
公共类阶乘扩展递归任务{
私人长p,q;
公因子(长p,长q){
这个,p=p;
这个。q=q;
}
@凌驾
公共BigInteger计算(){
if(q

我哪里做错了?我不认为这是Fork/Join的结果。请帮忙

Fork/Join可以并行计算。它是:给你一个恒定的增益(通过示例将时间除以4)。这取决于您拥有的实际CPU(例如,200个线程将只共享相同的4个CPU)

相比之下,阶乘(典型的算法)是
O(N!)
这意味着它增长得非常快

如果您为每一步创建一个新分支,那么分支和连接的开销将补偿并行化带来的收益

所以重要的是用另一种算法来计算阶乘,这种算法不是
O(N!)
。如果应用动态规划(继续中间结果),可以将其转换为
O(N)

我不知道你试图模仿的算法,我应该做的是画一个矩阵或是一些成对的计算,以便在我第二次需要它们时重用它们


查看您的代码,我可以看到每个阶乘方法执行都会引发两个子执行:
(p+q)/2,q
p,(p+q)/2+1
。。。或者类似的。如果每次阶乘方法都找到一个结果,并将其保存在一个映射中
[Pair->BigDecimal]
,则可以在方法的开头查询此缓存。使此映射成为类的成员(或通过参数传递),以便不同的方法调用共享该映射

factorial(p,q) {
   if (there is result for (p,q) in the map)
      return it
   else
   {
      normal computation (provokes two child invocations)
      save result into cache
   }
}

如果您需要计算大量的阶乘,那么您应该在您需要的范围内计算阶乘,然后重用它。您不能以有效的方式同时执行阶乘计算。有关使用BigInteger的性能提示:将新的BigInteger(“1”)替换为常量;用
biginger.valueOf(p)
替换新的biginger(“+p)
。这会更快,并尽可能重用以前创建的实例。@Maurício对于较大的n值,使用并行算法计算n!现在是已知最快的。请参阅