0

Let's say I have a loop that will do some math on an array x. Is it better to assign a temporary double inside the loop at each iteration or should I use the array[i] every time?

By better I mean performance-wise using C++. I wonder if C++ has some vectorization or cash optimization that I'm ruining?

Also what if I call a function using this array and I might need values of a function multiple times, so I usually do the same with functions. I assume this would be better than calling the function many times.

How about if the loop uses omp parallel, I assume this should be safe, correct?

for(int i=0; i<N; i++){
    double xi = X[i];
    double fi = f(xi);
    t[i] = xi*xi + fi + xi/fi;
}
Ismasou
  • 135
  • 5
  • Using temporary might avoid extra load due to aliasing issue (if `f(xi)` **can** modify `X[i]`). – Jarod42 Jul 30 '19 at 07:16
  • In addition, `f(xi)` might be not "pure" and return different values each time (as `rand()` for example). – Jarod42 Jul 30 '19 at 07:18
  • 3
    You **only** start worrying about micro-optimisations when you have **measured** your performance and found it not up to **stated requirements**. – n. m. could be an AI Jul 30 '19 at 07:19
  • 1
    @n.m. Agree - important keyword is *'micro'*, though, some general optimisation patterns still should be considered right from the start, e. g. using (and implementing) move-semantics, where reasonable, `reserve`ing `std::vector`'s capacity, if size is known in advance, using the result of `std::map::find` instead of doing a second lookup, ... – Aconcagua Jul 30 '19 at 07:43

2 Answers2

5

elcuco is correct. Any compiler worth it's salt will be able to optimise out something this trivial. What matters here is code readability, personally i find X[i] to be a little easier to look at in this situation.

I will note that if you are repeatedly making very long statements i.e X.something.something.darkside[i][j] it might make sense to use a clearly named reference i.e auto & the_emperor = X.something.something.darkside[i][j].

QCTDev
  • 166
  • 6
2

Modern compilers (last 10 years) will optimise it out. Don't worry about it.

EDIT:

This has been discussed in StackOverflow a few times: Will compiler optimize and reuse variable In C++, should I bother to cache variables, or let the compiler do the optimization? (Aliasing)

This official documentation explains it, IMHO it is -fmerge-all-constants -fivopts and maybe -ftree-coalesce-vars clang and MSCV have similar options, feel free to research them yourself or link them here.

In practice, when a compiler sees a memory read (a variable, or array value) it will read it into a register, and unless that not marked as volatile, the compiler can assume it did not change, and will not issue instructions to re-read it.

Having said the magical volatile word: It should not be used for threading. It should be used for hardware mapped memory (for example, video card memory or external ports).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
elcuco
  • 8,948
  • 9
  • 47
  • 69
  • Arrays – sure. Matter might change, though, if using `std::map` instead; index lookup (`operator[]`) is complex and even might change the data (if element is not found) – would the compiler be able to prove that dropping second lookup wouldn't discard any visible side effects? Only then it would be allowed to optimise it away... – Aconcagua Jul 30 '19 at 07:35
  • @elcuco do you have a source for this? im really curious how it works. – Sven van den Boogaart Jul 30 '19 at 07:38
  • @Aconcagua if the `[]` operator is marked `const` then there is no reason to re-read the value (call that operator). – elcuco Jul 30 '19 at 07:55
  • @elcuco Have you looked at `std::map`? It doesn't even provide a `const` version of... – Aconcagua Jul 30 '19 at 08:02
  • if the `[]` operator is not `const`, than the compiler will need to re-read the value, just as you suggest (internal implementation can return a different value after each read, that is correct). – elcuco Jul 30 '19 at 08:06