Reputation: 10614
When I divide a valarray by its first element, only the first element becomes 1 and others keep their original value.
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
arr=arr/arr[0]; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
The actual output is:
1 10 15 20 25
The expected output is:
1 2 3 4 5
Why is the actual output not as expected?
I use g++(4.8.1) with -std=c++11
Upvotes: 5
Views: 607
Reputation: 171413
The details of why this happens are due to implementation tricks used in valarray
to improve performance. Both libstdc++ and libc++ use expression templates for the results of valarray
operations, rather than performing the operations immediately. This is explicitly allowed by [valarray.syn] p3 in the C++ standard:
Any function returning a
valarray<T>
is permitted to return an object of another type, provided all the const member functions ofvalarray<T>
are also applicable to this type.
What happens in your example is that arr/arr[0]
doesn't perform the division immediately, but instead it returns an object like _Expr<__divide, _Valarray, _Constant, valarray<double>, double>
which has a reference to arr
and a reference to arr[0]
. When that object is assigned to another valarray
the division operation is performed and the result stored directly into the left-hand side of the assignment (this avoids creating a temporary valarray
to store the result and then copying it into the left-hand side).
Because in your example the left-hand side is the same object, arr
, it means that the reference to arr[0]
stored in the expression template refers to a different value once the first element in arr
has been updated with the result.
In other words, the end result is something like this:
valarray<double> arr{5, 10, 15, 20, 25};
struct DivisionExpr {
const std::valarray<double>& lhs;
const double& rhs;
};
DivisionExpr divexpr = { arr, arr[0] };
for (int i = 0; i < size(); ++i)
arr[i] = divexpr.lhs[i] / divexpr.rhs;
The first iteration of the for-loop will set arr[0]
to arr[0] / arr[0]
i.e. arr[0] = 1
, and then all subsequent iterations will set arr[i] = arr[i] / 1
which means the values don't change.
I'm considering making a change to the libstdc++ implementation so that the expression template will store a double
directly instead of holding a reference. This would mean arr[i] / divexpr.rhs
will always evaluate arr[i] / 5
and not use the updated value of arr[i]
.
Upvotes: 2
Reputation: 50568
This one works:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
auto v = arr[0];
arr=arr/v; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
The problem is that you are trying to use a value (arr[0]
) from an array that you are modifying at the same time (arr
).
Intuitively, once you have updated arr[0]
by doing arr[0]/arr[0]
, what value does it contain?
Well, that's the value that will be used from now on to divide the other values...
Please, note that the same applies for arr/=arr[0]
(first of all, arr[0]/arr[0]
takes place, than all the others, in a for loop or something like that).
Also note from the documentation that operator[]
of a std::valarray
returns a T&
. This confirms the assumption above: it is turned to 1
as the first step of your iteration, then all the other operations are useless.
By simply copying it solves the issue, as in the example code.
Upvotes: 4