1

today i was running some test to get a deeper understanding of which some instruction i have in my program, when i notice something unexpected. I run the following test to understand if it was slower using the BigDecimal pow method and then converting, or converting to double and using the 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()));

}

Here is a single output example:

test 1 in:1268 test 2 in:1358 test 3 in:1049 test 4 in:1308

Ok i found that it is better to convert and then using Math pow but... Wait, why the hell test1 is slower than test3 and in a similar way test 2 is slower than test4?

Running this more and more it is always the same. If i assign the returned value, it takes lesser then just calling the method.

Anyone does know the reason?

Robdll
  • 5,865
  • 7
  • 31
  • 51
  • 2
    I'd be a little surprised if the code was actually doing *anything*, since it can all be optimized out. You'd be better off writing a better benchmark. – Dave Newton Apr 23 '15 at 13:01
  • You are micro benchmarking the JVM, [which is not as trivial as it might seem.](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java). e.g. you might not have triggered all the optimization the JVM does in your first loop - so run the loop once without measuring it first. – nos Apr 23 '15 at 13:01
  • At the very least you need to place the above code in a subroutine and call that several times from `main`, to "warm up" the JITC. – Hot Licks Apr 23 '15 at 13:04
  • Those numbers are meaningless for many reasons. Try writing a good micro benchmark and compare again: http://nitschinger.at/Using-JMH-for-Java-Microbenchmarking – maasg Apr 23 '15 at 14:01
  • thanks everyone! I m gonna read some stuff about micro benchmark. Did not even know the existence of it. – Robdll Apr 24 '15 at 14:43

1 Answers1

0

Below are my personal views , correct me if i am wrong . I am not sure how accurate my answer will be , I saw the question tried it and now i have some view

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);
    }

Observations :

  • Each call to pow method creates a BigDecimal object
  • main calculation is done via intVal.pow(n) => BigInteger.pow (check return statement of BigDecimal pow code above)
  • Every BigInteger.pow creates a new object of BigInteger.pow (internal working of BigInteger.pow have been skipped)

now summary for BigDecimal EACH call to BigDecimal.pow creates the following major objects (other calculation seemed to be minor)

[in Java source code implementation of BigDecimal]

  • two new temporary BigInteger
  • one new temporary BigDecimal

for each call to pow we have 3 new temporary objects of subclasses of java.lang.Number(BigDecimal,BigInteger extent Number) created , this looks like a good point to compare in terms of time taken to run the code

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
    }

this uses StrictMath's static method pow , the source code can be found here in line 1511 of this link code was huge so i didnt paste here .

Observations :

  • static methods of Double class is used (i doubt that will lead to a major increase in execution time)
  • lot of operations on primitive types are used (that also should take less time to run)

my personal view/conclusion would be

BigDecimal creates a lot of objects when it executes the .pow method , which might be the reason of excessive time taken to execute

Accuracy of calculation of both methods is something beyond my knowledge and experience , so ill try explore on accuracy soon and update this answer

Srinath Ganesh
  • 2,496
  • 2
  • 30
  • 60