为什么分配方法返回使应用程序运行得比调用它更快?

时间:2015-04-23 12:59:13

标签: java

今天我正在进行一些测试,以便更深入地了解我的程序中有哪些指令,当我发现意外情况时。 我运行以下测试来了解使用BigDecimal pow方法然后转换,或转换为double并使用Math.pow它是否更慢。

public static void main(String[] args){

    BigDecimal myBd = new BigDecimal(2);

    Date start = new Date();
    System.out.println("inizio: " + start.toString());

    for(int i=0; i++<10000000;){
        Math.pow(myBd.doubleValue(),2); 
    }
    Date t1 = new Date();
    System.out.println("test 1 in:" +(t1.getTime() - start.getTime()));

    for(int i=0; i++<10000000;){
        myBd.pow(2);
    }
    Date t2 = new Date();
    System.out.println("test 2 in:" +(t2.getTime() - t1.getTime()));


    for(int i=0; i++<10000000;){
        double wtf = Math.pow(myBd.doubleValue(),2); 
    }
    Date t3 = new Date();
    System.out.println("test 3 in:" +(t3.getTime() - t2.getTime()));

    for(int i=0; i++<10000000;){
        double wtf = myBd.pow(2).doubleValue();
    }
    Date t4 = new Date();
    System.out.println("test 4 in:" +(t4.getTime() - t3.getTime()));

}

以下是单个输出示例:

  

测试1:1268   测试2:1358   测试3:1049   测试4:1308

好吧我发现转换然后使用Math pow更好但是......等等,为什么地狱test1比test3慢,并且以类似的方式测试2比test4慢?

越来越多地运行它总是一样的。如果我指定返回的值,则只需调用该方法即可。

任何人都知道原因吗?

1 个答案:

答案 0 :(得分:0)

以下是我的个人观点,如果我错了,请纠正我。 我不确定我的回答有多准确,我看到问题尝试了,现在我有了一些观点

  

的BigDecimal

BigDecimal.pow method source code

private volatile BigInteger intVal;
.
.
.
public BigDecimal pow(int n) {
        if (n < 0 || n > 999999999) {
            throw new ArithmeticException("Invalid operation");
        }
        // No need to calculate pow(n) if result will over/underflow.
        // Don't attempt to support "supernormal" numbers.
        int newScale = checkScale((long) scale * n);
        this.inflate();
        return new BigDecimal(intVal.pow(n), newScale);
    }

观察:

  • 每次调用pow方法都会创建一个BigDecimal对象
  • 主要计算通过 intVal.pow(n) =&gt;完成。 BigInteger.pow(检查上面BigDecimal pow代码的return语句)
  • 每个BigInteger.pow都会创建一个BigInteger.pow的新对象(已跳过BigInteger.pow的内部工作)

现在为BigDecimal汇总 每次调用BigDecimal.pow都会创建以下主要对象(其他计算似乎很小)

[在BigDecimal的Java源代码实现中]

  • 两个新的临时BigInteger
  • 一个新的临时BigDecimal

对于每次调用pow我们都创建了 3个新的临时对象的java.lang.Number(BigDecimal,BigInteger extent Number)的子类,这看起来像是一个比较好的时间点用来运行代码

  

Math.pow

Math.pow method source code

public static double pow(double a, double b) {
        return StrictMath.pow(a, b); // default impl. delegates to StrictMath
    }

这使用了StrictMath的静态方法pow,可以找到源代码here in line 1511 of this link代码很大,所以我没有在这里粘贴。

观察:

  • 使用Double类的静态方法(我怀疑这将导致执行时间的大幅增加)
  • 使用了对原始类型的大量操作(也应该花费更少的时间来运行)
  

我的个人观点/结论将是

BigDecimal在执行.pow方法时会创建很多对象,这可能是执行时间过长的原因

这两种方法的计算准确性超出了我的知识和经验,很快就尝试探索准确性并更新此答案