今天,当我发现意外情况时,我正在运行一些测试以更深入地了解程序中有哪些指令。
我运行以下测试以了解使用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慢,而test 2比test4慢?

越来越多地运行它总是相同的。如果我指定返回值,则花费更少,而只需调用该方法。

有人知道原因吗?

最佳答案

以下是我的个人看法,如果我做错了,请纠正我。
我不确定答案的准确性如何,我看到了问题的解决方法,现在我有了一些看法


  大十进制


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)=> BigInteger.pow完成(检查上面BigDecimal pow代码的返回语句)
每个BigInteger.pow都会创建一个BigInteger.pow的新对象(已跳过BigInteger.pow的内部工作)


现在是BigDecimal的摘要
每次调用BigDecimal.pow都会创建以下主要对象(其他计算似乎是次要的)

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


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


对于每次调用pow,我们创建了3个新的java.lang.Number(BigDecimal,BigInteger范围编号)子类的临时对象,这似乎是比较运行代码所需时间的好地方


  数学战利品


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方法时会创建很多对象,这可能是执行时间过长的原因

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

10-05 21:13
查看更多