简体   繁体   中英

C++ - how to improve this methods execution speed

I am trying to improve my programming skills for an assignment that will be released soon, it involves solving a problem while making it run as efficient and as fast as possible. I know this is a fairly restrained/small piece of code but how if anything would make it run faster.

the method takes an array with holds details of transactions, there are 100 as the number of transactions used to maintain the loop. so am getting the average num of shares and then returning it. not fluent english so hopefully it makes sense, thanks

double Analyser::averageVolume()
{
    // Your code
    double averageNumShares = 0;
    for(int i = 0; i < nTransactions; i++)
    {
        averageNumShares += tArray[i].numShares;
    }
    averageNumShares = averageNumShares / nTransactions;
    return averageNumShares;
    //return 0
}

If you need to compute the average of n numbers I'm afraid that you can't speed it up much past the linear-time approch in your sample code..

Unless this is used as part of another more complex algorithm where you might be able to get away with not having to compute the average or something along these lines, taking an average is going to be an O(n) operation which basically involves summing all elements of the array and one division by the number of elements. Which is exactly what you have.

Why not have two other values for the object - A running total and the number of items?

Then computing the average can make use of those numbers. Quickly and simply (could be an inline function!).

Here is one additional approach, similar to that suggested by Ed Heal that should be less sensitive to roundoff errors. The roundoff error of the average grows with the size of the accumulated sum. This may or may not be an issue for you, but it is something to be aware of.

Here is an iterative algorithm that minimizes roundoff error in the average, which I first came across in an old edition (circa 1998) of Ross :

double Analyser::averageVolume()
{
  double averageNumShares = 0.0;

  for (int i = 0; i < nTransactions; i++)
  {
    double delta = (tArray[i].numShares - averageNumShares) / (i+1);
    averageNumShares += delta;
  }

  return averageNumShares;
}

This works by deriving a recursive definition of the average. That is, given samples x[1] , ..., x[j] , ..., x[N] , you can calculate the average of the first M+1 samples from sample x[M+1] and the average of the first M samples:

sum(M) = x[1] + x[2] + ... + x[M]
thus avg(M+1) = sum(M+1)/(M+1) and avg(M) = sum(M)/M

avg(M+1) - avg(M) = sum(M+1)/(M+1) - sum(M)/M
    = [ M*sum(M+1) - (M+1)*sum(M) ]/[ M * (M+1) ]
    = [ M*(x[M+1] + sum(M)) - M*sum(M) - sum(M) ] / [ M*(M+1) ]
    = [ M*x[M+1] - sum(M) ] / [ M*(M+1) ]
    = [ x[M+1] - avg(M) ] / (M+1)
thus: avg(M+1) = avg(M) + [ x[M+1] - avg(M) ]/(M+1)

To get a sense of the roundoff error for the two approaches, try computing the average of 10^7 samples, each sample equal to 1035.41. Your original approach returns (on my hardware), an average of 1035.40999988683. The iterative approach above returns the exact average of 1035.41.

Both, unfortunately, are O(N) at some point. Your original scheme has N additions and one division. The iterative scheme has N additions, subtractions, and divisions, so you pay a bit more for the accuracy.

如果使用gcc,请更改优化级别。

Short answer: This code is as good as it gets with respect to speed. What you can tweak is how you compile it. Or obviously, rewrite it in assembly if that is an option.

"Stretched" answer: Now... if you really want to try getting better performance, have already tried using all compiler optimization flags and optimizations available, and you are ready to compromise code readability for possibly more speed, you could consider rewriting:

for(int i = 0; i < nTransactions; i++)
    {
        averageNumShares += tArray[i].numShares;
    }

as

pointerValue = &(tArray[0].numShares);
pointerIncrement = sizeof(tArray[0]);
for(int i = 0; i < nTransactions; i++)
    {
        averageNumShares += *(pointerValue++pointerIncrement);
    }

It could be that you get better performance by showing the compiler all you do is jump over a fixed offset at each loop iteration. A good compiler should be able to see that with your initial code. And the new code could get your worse performance. It really depends on the specifics of your compiler, and again, I do not recommend that approach unless you are desperate for better performance than what the compiler can offer, and don't want to jump to using in-line assembly or intrinsics (if any available).

int i= nTransactions;
while(i--){// test for 0 is faster
    averageNumShares += (q++)->numShares;// increment pointer is faster than offset
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM