0

Suppose that I have this program :

#include <iostream>

using namespace std;
int main() {
    unsigned int n, i;
    double sum = 0;
    cout << "\n No. of terms: ";
    cin >> n;
    for( i=1; i<=n; i++ ) {
        sum += i/(i+1.0);       //// THE LINE IN QUESTION
    }
    cout << " Sum = " << sum;
    return 0;
}

It calculates sum of series : 1/2 + 2/3 + 3/4 .. to n/n+1.

Now i want to ask that in the for loop where i wanted to assign int value to double variable sum, i can do that by two ways :

  1. method 1: sum += i/(i+1.0)
  2. method 2: sum += (double) i/(i+1)

Which is faster or better way?

Ligth races in orbits : What i mean is that which method should be used.

Max Payne
  • 2,423
  • 17
  • 32
  • 2
    Stop tagging this as C! Your code is clearly C++ code. Do not tag spam. – fuz Aug 16 '15 at 13:50
  • Method one contains one conversion from `int` to `double`, one floating point addition and one floating point division. The other contains two floating point conversions, one integer addition and one floating point division. I don't think there is much of a difference speed-wise. – fuz Aug 16 '15 at 13:53
  • You might want to look up the topic of [premature optimisation](http://stackoverflow.com/questions/516160/planning-for-efficiency-early-vs-premature-optimization). – Peter Aug 16 '15 at 13:58
  • @FUZxxl: There are same numbers of `int` to `double` conversion in both methods (and I agree with conclusion). – Jarod42 Aug 16 '15 at 13:59
  • @Jarod42 In the first method, `i` only needs to be converted once and every decent compiler sees that. – fuz Aug 16 '15 at 14:06
  • 1
    @FUZxxl : stop downvoting for no reason. Tagging is not spamming. After all it applied to C too. only that i had to write a snippet in C (that would make it open to a larger comm.) Please know about what you speak. Thanks for answer btw. – Max Payne Aug 16 '15 at 14:22
  • @TimKrul I haven't downvoted you. I'm currently preparing an answer, please standby for the time. Please realize that C and C++ are distinct languages and I'm sick of all the people being blatantly ignorant about that. Pick one language and you get an answer for that language. This site is not a “provide an answer for as many languages as possible” type service. – fuz Aug 16 '15 at 14:26
  • @FUZxxl But there are people who browse through particular tags .. like only C, or C++. My prob applies to both, and i hope to pose the question to more people, so that i may get better answers. I am in no way saying C and C++ are same. – Max Payne Aug 16 '15 at 14:29
  • @TimKrul Adding wrong tags to attract more people is the exact definition of “tag spamming.” Yes, your problem can be formulated for both C and C++ but you chose to do so for C++ so this is a C++ question now. You cannot ask the question for both. – fuz Aug 16 '15 at 14:32
  • Pick a language and stick with it for goodness's sake. Then explain what you mean by "faster" or "better", or this'll be closed as subjective. – Lightness Races in Orbit Aug 16 '15 at 14:36
  • 1
    Maybe someone will correct me, but AFAIK there's no issue in posting two separate questions, even if they are about the same thing in two different languages. No tag spamming, happy users. – Quentin Aug 17 '15 at 14:45

2 Answers2

1

As a rule of thumb, such minor differences aren't likely to matter. There is a difference of one or two cycles out of the roughly 20 or so cycles (most taken by the division) this is going to take, if there is one at all.

These are the operations your two methods perform:

Method 1

a   = (double)i; // convert to double
b   = 1.0;       // load double
c   = a + b;     // double addition
sum = a / c;     // double division

Notice that we only have to do one conversion to double as the compiler can do an optimization called common subexpression elimination. On many machines (like x86) you cannot simply add a floating point constant to a number, you have to load the constant into a floating point register first so I count that as an extra instruction. If you are doing this in a loop, the 1.0 needs to be loaded only once though.

Method 2

a   = (double)i; // convert to double
b   = i + 1;     // int addition
c   = (double)b; // convert to double
sum = a / c;     // double division

Here we need to do two conversions but we can save a floating point load and we can replace a floating point addition with a cheaper integer addition.

Machine code

Here is amd64 assembly for both methods:

method1:
        pxor     %xmm0, %xmm0      // clear result register
        movsd    .one(%rip), %xmm1 // load 1.0
        cvtsi2sd %edi, %xmm0       // convert int to double
        addsd    %xmm0, %xmm1      // double addition
        divsd    %xmm1, %xmm0      // double division

.one:
        .double 1.0

method2:
        pxor     %xmm0, %xmm0      // clear result register
        pxor     %xmm1, %xmm1      // clear register for i + 1
        cvtsi2sd %edi, %xmm0       // convert int to double
        addl     $1, %edi          // increment
        cvtsi2sd %edi, %xmm1       // convert int to double
        divsd    %xmm1, %xmm0      // double division

Both methods seem to be pretty equal in terms of operations. I recommend you to benchmark this if you want to be sure.

fuz
  • 88,405
  • 25
  • 200
  • 352
1

Method one results in two conversions from integer to double, one double addition, and one double division.

Method two results in a conversion from integer to double, an integer addition, converting the integer result to double, and one double division.

It's fairly likely that the compiler will optimize two identical conversions of integer to double in method 1. I don't believe that a compiler will ever optimize the first method down to the second one, due to integer overflow-related issues, so I'll just assume a reasonably intelligent compiler that can execute the obvious optimization.

So we have:

  1. Convert integer to double
  2. Double addition
  3. Double division

Versus:

  1. Convert integer to double
  2. Integer addition
  3. Convert integer to double
  4. Double division

So the difference between the two methods reduces to a double addition operation versus integer addition and conversion of integer to double.

Regarding "which one is faster": the difference is not directly comparable, so this will depend entirely on whichever CPU is going to execute this. I don't know of any empirical evidence that all CPUs will handle one or the other set of operations always faster than the other one.

Regarding "which one is better": the better approach is the one that you think is more readable, and maintainable. That's because whichever approach turns out to be faster in practice, the "faster" part will so insignificant, on modern CPUs, that it can be practically ignored, and the remaining factor to consider is simply readability and maintainability; and insofar which one of the two approaches is more readable or maintainable, this is going to be purely a matter of one's taste.

Unless, of course, one has to implement something like this in certain very narrow, tailored, situations where every nanosecond matters, and a huge pile of money depends entirely on the proposition that "faster=better". In which case the only way to obtain the answer is to rigorously benchmark the execution profiles of both methods on your target hardware platform, and figure out by yourself which one is "better".

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148