Math.pow() performance question…

I’ve recently had a discussion with a colleague on whether it is a good practice using Math.pow() to square a number?

My friend’s argument is that Math.pow() is designed to raise a number to a partial power, such as 7^2.5.  Therefore it will use complicated and inefficient math raising a number to 2.0 instead of more efficient way of simply x*x.  He advocated implementing and using a square function below instead of using Math,pow( x, 2.0);

So the question remains:

A) public static double square( double x ){ return x * x; }

or

B) Math.pow( x, 2.0 );

?????

Please give us your input!

———————————————

pow

public static double pow(double a,
                         double b)
Returns the value of the first argument raised to the power of the second argument. Special cases:

  • If the second argument is positive or negative zero, then the result is 1.0.
  • If the second argument is 1.0, then the result is the same as the first argument.
  • If the second argument is NaN, then the result is NaN.
  • If the first argument is NaN and the second argument is nonzero, then the result is NaN.
  • If
    • the absolute value of the first argument is greater than 1 and the second argument is positive infinity, or
    • the absolute value of the first argument is less than 1 and the second argument is negative infinity,

    then the result is positive infinity.

  • If
    • the absolute value of the first argument is greater than 1 and the second argument is negative infinity, or
    • the absolute value of the first argument is less than 1 and the second argument is positive infinity,

    then the result is positive zero.

  • If the absolute value of the first argument equals 1 and the second argument is infinite, then the result is NaN.
  • If
    • the first argument is positive zero and the second argument is greater than zero, or
    • the first argument is positive infinity and the second argument is less than zero,

    then the result is positive zero.

  • If
    • the first argument is positive zero and the second argument is less than zero, or
    • the first argument is positive infinity and the second argument is greater than zero,

    then the result is positive infinity.

  • If
    • the first argument is negative zero and the second argument is greater than zero but not a finite odd integer, or
    • the first argument is negative infinity and the second argument is less than zero but not a finite odd integer,

    then the result is positive zero.

  • If
    • the first argument is negative zero and the second argument is a positive finite odd integer, or
    • the first argument is negative infinity and the second argument is a negative finite odd integer,

    then the result is negative zero.

  • If
    • the first argument is negative zero and the second argument is less than zero but not a finite odd integer, or
    • the first argument is negative infinity and the second argument is greater than zero but not a finite odd integer,

    then the result is positive infinity.

  • If
    • the first argument is negative zero and the second argument is a negative finite odd integer, or
    • the first argument is negative infinity and the second argument is a positive finite odd integer,

    then the result is negative infinity.

  • If the first argument is finite and less than zero
    • if the second argument is a finite even integer, the result is equal to the result of raising the absolute value of the first argument to the power of the second argument
    • if the second argument is a finite odd integer, the result is equal to the negative of the result of raising the absolute value of the first argument to the power of the second argument
    • if the second argument is finite and not an integer, then the result is NaN.
  • If both arguments are integers, then the result is exactly equal to the mathematical result of raising the first argument to the power of the second argument if that result can in fact be represented exactly as a double value.

(In the foregoing descriptions, a floating-point value is considered to be an integer if and only if it is finite and a fixed point of the method ceil or, equivalently, a fixed point of the method floor. A value is a fixed point of a one-argument method if and only if the result of applying the method to the value is equal to the value.)

The computed result must be within 1 ulp of the exact result. Results must be semi-monotonic.

Parameters:
a – the base.
b – the exponent.
Returns:
the value ab.

5 Responses to “Math.pow() performance question…”

  1. Mike Gray says:

    I would always do x*x when the power is 2. Method calls are more expensive, relatively speaking, than just doing the simple math inline and in the end, Math.pow() is going to end up doing roughly the same thing with more overhead.

    In addition, I think it enhances the readability when I read x*x versus having to mentally parse what Math.pow(x, 2) is doing. It’s a minor point, but anything that increases readability AND increases performance is a good thing, as the two are opposition many times.

    Finally, with respect to implementing a custom square method, you may not even improve things. I’d be very surprised if the implementation for Math.pow doesn’t consider whether the power is a whole number and do it the same way your square function would. And that’s if the compiler doesn’t optimize the call in the first place. Also, a square method has the same problem as Math.pow() with respect to overhead for making repeated method calls.

  2. Bill D says:

    Math.pow() is hugely inefficient, at least 15 times worse than multiplication in Java 1.5. For readability purposes you have to draw the line at some integer value of N for which you switch from multiplication to using pow(), but for squaring and cubing (probably 99% of the cases for integer exponents) you should never use pow().

  3. javajiggle says:

    Bill D. that is very interesting. Can you please clarify whether Math.pow() is 15 times worse than multiplying two numbers x*x, or is it 15 times worse that calling a function that returns two multiplied numbers, like square(x) ?

    Also, do you have a test program or a source?

  4. John Buckwell says:

    Just been coding a processor intensive application that needs to calculate millions of squares so this is an interesting question.

    A simple test for 10 million repetions shows x * x is 20 – 25 times faster than Math.pow(x, 2.0). Calling x*x in a method made only marginal difference.

    Test code is below. The purpose of the “if (r > 200.0) f1 = f2;” statement is to ensure the compile is not optimising the code by inserting the same result for repeated calls to a function with the same parameter values. It made almost no difference to the run times.

    Date date;
    long startTime; // in milliseconds
    long endTime;
    double f1 = 15.69;
    double f2 = 17.01;
    double r = 0;
    int cycles = 10000000;

    date = new Date();
    startTime = date.getTime();
    for (int i = 0; i 200.0) f1 = f2;
    }
    date = new Date();
    endTime = date.getTime();
    System.out.println(“f * f runtime for “+cycles+” cycles: ” + ((endTime – startTime)) + ” milliseconds\r”);

    date = new Date();
    startTime = date.getTime();
    for (int i = 0; i 200.0) f1 = f2;
    }
    date = new Date();
    endTime = date.getTime();
    System.out.println(“square(f) runtime for “+cycles+” cycles: ” + ((endTime – startTime)) + ” milliseconds\r”);

    date = new Date();
    startTime = date.getTime();
    double two = 2.0;
    for (int i = 0; i 200.0) f1 = f2;
    }
    date = new Date();
    endTime = date.getTime();
    System.out.println(” Math.pow(f1, two) runtime for “+cycles+” cycles: ” + ((endTime – startTime)) + ” milliseconds\r”);

  5. John Buckwell says:

    Just read my comment and seen the cut and paste of the test code didn’t work as intended. Sorry you will have to write your own code but I stand by the results!

Leave a Reply