Math.Pow vs multiply operator (performance)
Asked Answered
O

9

52

Anyone knows if multiply operator is faster than using the Math.Pow method? Like:

n * n * n

vs

Math.Pow ( n, 3 )
Orlantha answered 1/6, 2009 at 20:14 Comment(2)
The way to achieve performance is (1) set meaningful goals, (2) measure to see if you've met your goals, (3) find the slowest thing if you haven't, (4) optimize the slowest thing until your goal is met. If you have to ask us which is faster then you haven't done steps (2) or (3), and so it is premature to do step (4).Holophytic
+Eric Lippert that's true, but it can also be interesting to find out if languages do some magical optimization :PRoundlet
F
38

Basically, you should benchmark to see.

Educated Guesswork (unreliable):

In case it's not optimized to the same thing by some compiler...

It's very likely that x * x * x is faster than Math.Pow(x, 3) as Math.Pow has to deal with the problem in its general case, dealing with fractional powers and other issues, while x * x * x would just take a couple multiply instructions, so it's very likely to be faster.

Favianus answered 1/6, 2009 at 20:16 Comment(10)
why do you believe this to be very likely?Incendiary
It takes two integer multiply instructions. In case Math.Pow is not optimized out to the same thing, it probably does much more work (remember, it has to solve a much more general problem, such as fractional powers...)Favianus
"It's very likely that x * x * x is faster than Math.Pow (completely guesswork)." Something seems off in this sentence.Binetta
You can always open up System.Math in reflector and check it out. My personal guess is that there's more overhead (possibly negligible granted)to allow it to be a general purpose function, rather than a discrete mathematical calculation.Slaby
I think System.Math is implemented as InternalCall. I haven't checked it though.Favianus
@Mehrdad: Thanks for the additional explanation - I have no disagreement.Incendiary
@divo: Indeed, it wasn't really guesswork. It was previous tests that resulted this. I wanted to point out that it really depends on the particular infrastructure that's running your code and you should always rely on benchmarking rather than guessing.Favianus
is that also valid for java and scala?Catrinacatriona
I benchmarked this with Pow(x, 2) and Pow(x, 3). Multiplication was always more than 100x faster (optimized in Debug and Release). One can safely prefer simple multiplication over Pow functions.Speculum
This does not really seem like an answer to me.Pentagon
I
50

I just reinstalled windows so visual studio is not installed and the code is ugly

using System;
using System.Diagnostics;

public static class test{

public static void Main(string[] args){
    MyTest();
    PowTest();
}

static void PowTest(){
    var sw = Stopwatch.StartNew();
    double res = 0;
    for (int i = 0; i < 333333333; i++){
        res = Math.Pow(i,30); //pow(i,30)
    }
    Console.WriteLine("Math.Pow: " + sw.ElapsedMilliseconds + " ms:  " + res);
}

static void MyTest(){
    var sw = Stopwatch.StartNew();
    double res = 0;
    for (int i = 0; i < 333333333; i++){
        res = MyPow(i,30);
    }
    Console.WriteLine("MyPow: " + sw.ElapsedMilliseconds + " ms:  " + res);
}



static double MyPow(double num, int exp)
{
    double result = 1.0;
    while (exp > 0)
    {
        if (exp % 2 == 1)
            result *= num;
        exp >>= 1;
        num *= num;
    }

    return result;
}
}

The results:
csc /o test.cs

test.exe

MyPow: 6224 ms:  4.8569351667866E+255  
Math.Pow: 43350 ms:  4.8569351667866E+255 

Exponentiation by squaring (see https://mcmap.net/q/99126/-the-most-efficient-way-to-implement-an-integer-based-power-function-pow-int-int) is much faster than Math.Pow in my test (my CPU is a Pentium T3200 at 2 Ghz)

EDIT: .NET version is 3.5 SP1, OS is Vista SP1 and power plan is high performance.

Ivonneivor answered 1/6, 2009 at 21:33 Comment(5)
Thanks. Your method seems very good. Is it even better than nnn?Orlantha
It requires two multiplications, just like nnn, but with some overhead, so it will be slightly worse... For an exponent of four (or higher) it may be better than nnn*n though, as it still requires only two multiplications, while the direct approach needs three.Truax
MyPow() works just only for positive numbers. It should starts with if (exp< 0) return (1 / MyPow(num, Math.Abs(exp)));Picoline
You can eek a ~1.5% performance increase by changing modulus to bitwise check i.e. (exp % 2 == 1) -> ((exp & 1) != 0)Kyanite
I just ran this on my laptop but as a .NET Core 2.1 console app and I get the results: MyPow: 23545 ms, Math.Pow: 21109 ms. So obviously MS has improved the performance a lot since this was posted.Leveille
F
38

Basically, you should benchmark to see.

Educated Guesswork (unreliable):

In case it's not optimized to the same thing by some compiler...

It's very likely that x * x * x is faster than Math.Pow(x, 3) as Math.Pow has to deal with the problem in its general case, dealing with fractional powers and other issues, while x * x * x would just take a couple multiply instructions, so it's very likely to be faster.

Favianus answered 1/6, 2009 at 20:16 Comment(10)
why do you believe this to be very likely?Incendiary
It takes two integer multiply instructions. In case Math.Pow is not optimized out to the same thing, it probably does much more work (remember, it has to solve a much more general problem, such as fractional powers...)Favianus
"It's very likely that x * x * x is faster than Math.Pow (completely guesswork)." Something seems off in this sentence.Binetta
You can always open up System.Math in reflector and check it out. My personal guess is that there's more overhead (possibly negligible granted)to allow it to be a general purpose function, rather than a discrete mathematical calculation.Slaby
I think System.Math is implemented as InternalCall. I haven't checked it though.Favianus
@Mehrdad: Thanks for the additional explanation - I have no disagreement.Incendiary
@divo: Indeed, it wasn't really guesswork. It was previous tests that resulted this. I wanted to point out that it really depends on the particular infrastructure that's running your code and you should always rely on benchmarking rather than guessing.Favianus
is that also valid for java and scala?Catrinacatriona
I benchmarked this with Pow(x, 2) and Pow(x, 3). Multiplication was always more than 100x faster (optimized in Debug and Release). One can safely prefer simple multiplication over Pow functions.Speculum
This does not really seem like an answer to me.Pentagon
C
16

A few rules of thumb from 10+ years of optimization in image processing & scientific computing:

Optimizations at an algorithmic level beat any amount of optimization at a low level. Despite the "Write the obvious, then optimize" conventional wisdom this must be done at the start. Not after.

Hand coded math operations (especially SIMD SSE+ types) will generally outperform the fully error checked, generalized inbuilt ones.

Any operation where the compiler knows beforehand what needs to be done are optimized by the compiler. These include: 1. Memory operations such as Array.Copy() 2. For loops over arrays where the array length is given. As in for (..; i<array.Length;..)

Always set unrealistic goals (if you want to).

Chilblain answered 8/6, 2011 at 3:7 Comment(0)
V
10

I just happened to have tested this yesterday, then saw your question now.

On my machine, a Core 2 Duo running 1 test thread, it is faster to use multiply up to a factor of 9. At 10, Math.Pow(b, e) is faster.

However, even at a factor of 2, the results are often not identical. There are rounding errors.

Some algorithms are highly sensitive to rounding errors. I had to literally run over a million random tests until I discovered this.

Vltava answered 20/5, 2012 at 12:10 Comment(3)
Thanks so which one is better to use to minimize rounding errors?Orlantha
The Power formula is best for accuracy. However, it depends on the input. For a vast range of numbers, the results are identical. I suggest you test them for your case usage.Vltava
If you used y = x * x; z = x * y * y; return z * z for a total of 4 multiplications, to calculation x^10, it would probably be faster that Math.Pow() again. As for accuracy, Math.Pow() will likely be somewhat more accurate, but only slightly. Math.Pow(b,e) is calculated by exp(e * log(b)) (probably with some optimization).Mulligan
A
5

This is so micro that you should probably benchmark it for specific platforms, I don't think the results for a Pentium Pro will be necessarily the same as for an ARM or Pentium II.

All in all, it's most likely to be totally irrelevant.

Archive answered 1/6, 2009 at 20:22 Comment(0)
P
4

I checked, and Math.Pow() is defined to take two doubles. This means that it can't do repeated multiplications, but has to use a more general approach. If there were a Math.Pow(double, int), it could probably be more efficient.

That being said, the performance difference is almost certainly absolutely trivial, and so you should use whichever is clearer. Micro-optimizations like this are almost always pointless, can be introduced at virtually any time, and should be left for the end of the development process. At that point, you can check if the software is too slow, where the hot spots are, and spend your micro-optimization effort where it will actually make a difference.

Puritan answered 1/6, 2009 at 20:29 Comment(0)
C
2

Let's use the convention x^n. Let's assume n is always an integer.

For small values of n, boring multiplication will be faster, because Math.Pow (likely, implementation dependent) uses fancy algorithms to allow for n to be non-integral and/or negative.

For large values of n, Math.Pow will likely be faster, but if your library isn't very smart it will use the same algorithm, which is not ideal if you know that n is always an integer. For that you could code up an implementation of exponentiation by squaring or some other fancy algorithm.

Of course modern computers are very fast and you should probably stick to the simplest, easiest to read, least likely to be buggy method until you benchmark your program and are sure that you will get a significant speedup by using a different algorithm.

Cheffetz answered 1/6, 2009 at 20:39 Comment(0)
V
2

Math.Pow(x, y) is typically calculated internally as Math.Exp(Math.Log(x) * y). Evey power equation requires finding a natural log, a multiplication, and raising e to a power.

As I mentioned in my previous answer, only at a power of 10 does Math.Pow() become faster, but accuracy will be compromised if using a series of multiplications.

Vltava answered 22/7, 2017 at 9:2 Comment(0)
P
0

I disagree that handbuilt functions are always faster. The cosine functions are way faster and more accurate than anything i could write. As for pow(). I did a quick test to see how slow Math.pow() was in javascript, because Mehrdad cautioned against guesswork

    for (i3 = 0; i3 < 50000; ++i3) { 
      for(n=0; n < 9000;n++){ 
        x=x*Math.cos(i3);
      }
    }

here are the results:

Each function run 50000 times 

time for 50000 Math.cos(i) calls = 8 ms 
time for 50000 Math.pow(Math.cos(i),9000) calls = 21 ms 
time for 50000 Math.pow(Math.cos(i),9000000) calls = 16 ms 
time for 50000 homemade for loop calls 1065 ms

if you don't agree try the program at http://www.m0ose.com/javascripts/speedtests/powSpeedTest.html

Prevailing answered 20/11, 2011 at 18:31 Comment(1)
This is not very informative. in your custom version you call Math.cos multiple times, while for Mathe.pow it is called once as parameter. So for a real test replace x = x * math... with x = x * c; and insert between the two for a c = Math.cos...Ablution

© 2022 - 2024 — McMap. All rights reserved.