Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用逐位运算优化Java数学_Java - Fatal编程技术网

使用逐位运算优化Java数学

使用逐位运算优化Java数学,java,Java,在我的Java类中,我必须使用Bailey–Borwein–Plouffe公式计算精确到小数点后15位的Pi值。在公式中,我需要计算16乘以n的幂(从1到50000的整数) 这就是我正在使用的公式 这是我的计算代码: double value = 0.0; //Calculates and increments value by using the BBP formula for(int i = 0; i < iterations; i++) { if(i == 0) {

在我的Java类中,我必须使用Bailey–Borwein–Plouffe公式计算精确到小数点后15位的Pi值。在公式中,我需要计算16乘以n的幂(从1到50000的整数)

这就是我正在使用的公式

这是我的计算代码:

double value = 0.0;

//Calculates and increments value by using the BBP formula
for(int i = 0; i < iterations; i++) {
    if(i == 0) {
        value += (1 / 1) * (
                 (4.0 / ((8 * i) + 1)) - 
                 (2.0 / ((8 * i) + 4)) - 
                 (1.0 / ((8 * i) + 5)) - 
                 (1.0 / ((8 * i) + 6)) );
    } else {
        value += (1.0 / (2L<<(i<<2L))) * (
                 (4.0 / ((8 * i) + 1)) - 
                 (2.0 / ((8 * i) + 4)) - 
                 (1.0 / ((8 * i) + 5)) - 
                 (1.0 / ((8 * i) + 6)) );
    }
}
双值=0.0;
//使用BBP公式计算并增加值
对于(int i=0;ivalue+=(1.0/(2L可以表示为大于零的双精度的最小值是2-2048。对于上面(2048/4)的每一项,该公式都将以双精度的形式达到零,即512。增加到50000000太远了。

您只需要15位数字吗?给您:

class Class {
  private static final int ITERATION_COUNT = 15;


  public static void main(final String... args) {
    System.out.println(generatePi());
  }

  private static double generatePi() {
    double pi = 0;
    long sixteenPowK = 1;
    for (int k = 0; k < ITERATION_COUNT; k++) {
      pi += 1.0 / sixteenPowK * kthTerm(k);
      sixteenPowK *= 16;
    }
    return pi;
  }

  private static double kthTerm(final int k) {
    return 4.0 / (8.0 * k + 1) 
      - 2.0 / (8.0 * k + 4) 
      - 1.0 / (8.0 * k + 5) 
      - 1.0 / (8.0 * k + 6);
  }
}
类{
私有静态最终整数迭代计数=15;
公共静态void main(最终字符串…参数){
System.out.println(generatePi());
}
专用静态双生成器{
双pi=0;
长十六周=1;
for(int k=0;k<迭代次数;k++){
pi+=1.0/十六周*kthTerm(k);
十六周*=16;
}
返回pi;
}
专用静态双kthTerm(最终整数k){
回报率4.0/(8.0*k+1)
-2.0/(8.0*k+4)
-1.0/(8.0*k+5)
-1.0/(8.0*k+6);
}
}

我很想看到一个微型基准

免责声明:我远非数值方法方面的专家

一般来说,为了解决任何问题,我都避免预先优化。一旦我找到了解决方案,我就开始优化,只有在某种程度上需要的时候

在这种情况下,我将
8*I
乘法内联到
factor8
变量中,在循环中删除了
if
,并计算了
I=0
的初始值,最重要的是,我在乘法中累积了
(1/16)^I
的值

通过这些更改,我成功地计算出PI值,仅在
11次迭代中精确到15位小数。以下是代码:

public class Pi {

    public static void main(String[] args) {

        int iterations = 11;
        int start = 1;

        double value = 4.0 - 2.0 / 4.0 - 1.0 / 5.0 - 1.0 / 6.0;

        double oneSixteenth = 1.0 / 16.0;
        double oneSixteenthToN = oneSixteenth;

        for (int i = start; i < iterations; i++) {
            double factor8 = 8.0 * i;
            value += oneSixteenthToN * (
                    (4.0 / (factor8 + 1)) -
                            (2.0 / (factor8 + 4)) -
                            (1.0 / (factor8 + 5)) -
                            (1.0 / (factor8 + 6)));
            oneSixteenthToN *= oneSixteenth;
        }

        System.out.println("value = " + value); // our calculated value

        System.out.println("   pi = " + Math.PI); // exact value
    }
}

我必须承认,我不知道代码中累积错误的原因,但我几乎可以肯定这与
(1/16)的计算有关^i
term.

我已经解决了我自己的问题。事实证明,我根本不需要按位运算。由于程序创建了50万次迭代来计算Pi,我可以使用+=和*=运算来增加预定义变量。这是我的最终代码,它在0.2秒内以50万次迭代计算Pi

//Computes Pi by using the BBP formula
public double computePi(int iterations) //<=50 000 000
{
    final double d = 1 / 16.0;
    double a = 16.0;
    double b = -8;

    double pi = 0.0;

    for(int k = 0; k < iterations; k++)
    {
        a *= d;
        b += 8;
        pi += a * (4.0 / (b + 1)
                - 2.0 / (b + 4)
                - 1.0 / (b + 5)
                - 1.0 / (b + 6));

    }

    return pi;
}
//使用BBP公式计算Pi

公共双计算PI(整数迭代)//您不需要每次从头开始计算功耗。每个连续项都乘以一个系数,该系数是前一项的1/16。不能保证位移位操作会使您的程序更快。在您真正做到这一点之前,我建议您坚持纯数学并相信(JIT)编译器大多数现代CPU的乘法速度与它们的移位速度一样快。从我看来,唯一能让它更快的方法是并行化每个迭代。正如@ControlAltDel所说,你不能保证使用不同的数学运算会更快。不确定是否优化了它,但删除了
(1/1)
完全没有坏处。实际上,只需计算
0处的值,然后在
1处开始
i
就可以删除if语句。基本上
int value=4-1/2-1/5-1/6;for(int i=1;i
。那么你有什么建议吗?我尝试使用Math.exp计算幂(Math.log(16)*i),但计算时间仍然太长。或者,将
迭代次数设置为不超过大约520次,或者如果
i>520
15次迭代可能不会给出15位数字,则将附加项设置为零(尽管由于每个项都小于前一项的1/16,我想它必须)。只要
(kthTerm(k)==0.0)
所有这些方法都能以极快的编译时间完美地工作。但是,我的作业需要5000万次迭代。不过,多亏了你们,我确实重新思考了我的计算方法:)@Andrewmcguiness,我同意不能保证n次迭代将提供n个10位数的精度。但是在15位数的特定情况下,15次迭代就足够了。@ElectricFountainCo,50次迭代对于15位数来说是一个很大的浪费。但是,如果你想将pi计算到100万位数,请放心。看看
java.math.BigDecimal
,它将帮助您完成繁重的工作。@Andreas这是本作业的重点。我们接到一项任务,我们必须尽可能优化它。我们班的一些学生在0.2秒内计算了50万次Pi。
//Computes Pi by using the BBP formula
public double computePi(int iterations) //<=50 000 000
{
    final double d = 1 / 16.0;
    double a = 16.0;
    double b = -8;

    double pi = 0.0;

    for(int k = 0; k < iterations; k++)
    {
        a *= d;
        b += 8;
        pi += a * (4.0 / (b + 1)
                - 2.0 / (b + 4)
                - 1.0 / (b + 5)
                - 1.0 / (b + 6));

    }

    return pi;
}