valarray divide its element - c++

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

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.

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 of valarray<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].

Related

Visual studio 2019 Non-legit optimization in map::operator[]? [duplicate]

I just encountered a weird bug in my code (C++14) caused by the unexpected (for me at least) behavior of std::map. Here's a simple example demonstrating the behavior:
#include <iostream>
#include <map>
int main()
{
std::map<int, int> m;
for(int i = 0; i < 3; ++i) {
m[m.size()] = m.size();
}
for(const std::pair<int, int>& e : m) {
std::cout << e.first << " " << e.second << std::endl;
}
return 0;
}
This prints:
0 1
1 2
2 3
I was expecting:
0 0
1 1
2 2
What is going on here? The map first adds a new element with first set and only then (when the map's size has already increased) sets second? I don't quite understand why this would make sense. Or is there some other explanation? Thanks!
There is a few thing that happens in the expression
m[m.size()] = m.size();
First, m[m.size()] and = m.size() need to be evaluated. In C++14, that evaluation order is indeterminately sequenced. m[m.size()] might happen first, or it might happen second. If it happens first, then you see the results you received. If it happens second, then you get the output that you expected.
If you want
0 0
1 1
2 2
Then you need to guarantee that ordering yourself. You can use map::insert() to do just that:
m.insert(m.size(), m.size());
Starting in C++17, this is no longer the case. The standard was changed to say:
The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand; their result is an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
It now guarantees that = m.size() happens before m[m.size()], and you get the order that you expect.
Let's write down the loop code in a more elaborate way:
for(int i = 0; i < 3; ++i) {
int& temp = m.operator[](m.size());
temp = m.size();
}
Note that calling operator[] already does the insertion of an default initialized element before you assign a value to it. Therefore, the map has already grown by the time the right hand side of the assignment is evaluated.
To fix the issue, make sure the size is determined before you use operator[]:
for(int i = 0; i < 3; ++i) {
size_t v = m.size();
m[v] = v;
}

Inserting its own size to std::map

I just encountered a weird bug in my code (C++14) caused by the unexpected (for me at least) behavior of std::map. Here's a simple example demonstrating the behavior:
#include <iostream>
#include <map>
int main()
{
std::map<int, int> m;
for(int i = 0; i < 3; ++i) {
m[m.size()] = m.size();
}
for(const std::pair<int, int>& e : m) {
std::cout << e.first << " " << e.second << std::endl;
}
return 0;
}
This prints:
0 1
1 2
2 3
I was expecting:
0 0
1 1
2 2
What is going on here? The map first adds a new element with first set and only then (when the map's size has already increased) sets second? I don't quite understand why this would make sense. Or is there some other explanation? Thanks!
There is a few thing that happens in the expression
m[m.size()] = m.size();
First, m[m.size()] and = m.size() need to be evaluated. In C++14, that evaluation order is indeterminately sequenced. m[m.size()] might happen first, or it might happen second. If it happens first, then you see the results you received. If it happens second, then you get the output that you expected.
If you want
0 0
1 1
2 2
Then you need to guarantee that ordering yourself. You can use map::insert() to do just that:
m.insert(m.size(), m.size());
Starting in C++17, this is no longer the case. The standard was changed to say:
The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand; their result is an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.
It now guarantees that = m.size() happens before m[m.size()], and you get the order that you expect.
Let's write down the loop code in a more elaborate way:
for(int i = 0; i < 3; ++i) {
int& temp = m.operator[](m.size());
temp = m.size();
}
Note that calling operator[] already does the insertion of an default initialized element before you assign a value to it. Therefore, the map has already grown by the time the right hand side of the assignment is evaluated.
To fix the issue, make sure the size is determined before you use operator[]:
for(int i = 0; i < 3; ++i) {
size_t v = m.size();
m[v] = v;
}

Can I rely on std::map::operator[] to touch?

I have a C++ program in which I want to insert default values for any keys missing in a std::map. I'm thinking the easiest way to do this would be to use std::map::operator[]() like the POSIX touch command - that is, to leave the value unchanged if it already exists, but to create it if it doesn't. For example,
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> keys = {0, 1};
map<int, int> m;
m[1] = 5;
m[2] = 12;
for (const int i : keys)
{
m[i]; // touch value
}
for (auto const & kv : m)
{
cout << kv.first << ", " << kv.second << endl;
}
}
Can I be sure that the compiler won't optimize out the m[i]; statements, since I'm not "doing" anything with them? (Not explicitly assigning to, not reading from.)
Yes you can be sure. Optimizing the call away would change the observable behavior of your program, and the compiler is not allowed to do this (except in the case of RVO).
This is known as the as-if rule.
Yes, you can be sure. It's perhaps more intuitive when you consider that the line in question is equivalent to this:
m.operator[](i);
…and you don't expect arbitrary function calls to be optimised out of your program, if they do anything.
The [] operator does indeed default-construct the value that would be at that key's location if you do not assign it something.
Reference Link
If k does not match the key of any element in the container, the
function inserts a new element with that key and returns a reference
to its mapped value. Notice that this always increases the container
size by one, even if no mapped value is assigned to the element (the
element is constructed using its default constructor).

std::vector operator==: value or reference comparison?

So, I was trying to come up with a solution for When does x==x+2 in C++ on codegolf, and came up with this snippet only to realize that I don't know how it works. I'm not sure why both of these conditions evaluate to true.
Does anyone know if the line labeled line: is true because x==&x or because x+2 is evaluated before the left-hand side of ==?
#include <iostream>
#include <vector>
std::vector<int>& operator+ ( std::vector<int> &v, int val )
{
v.push_back(val);
return v;
}
int main()
{
std::vector<int> x;
std::vector<int> y = x + 2; // y is a copy of x, and x is [2]
// how are both of these are true?
std::cout << (x==y) << "\n"; // value comparison [2]==[2]
line:
std::cout << (x==x+2) << "\n"; // reference comparison? &x == &(x+2)
// not sure if this is relevant
std::cout << (x+2==x) << "\n"; // also true
return 0;
}
It seems--since vectors appear to be compared by value--that if x were evaluated before x+2, then x wouldn't be equal to x+2 (by value). I'm probably missing something obvious. Thanks in advance.
For the standard containers, operator== is overloaded as std::equal. This in turn works on itera­tors and applies comparison by dereferncing, as in *it1 == *it2. Therefore, no copies are required.
The expression x == x + 2 is the same as operator==(x, x + 2). Both operands are evaluated before the function call, and since x + 2 modifies x, both operands are the same. Thus the equality holds.
The surprise is the result of your unconventional design choice in overloading the +-operator. This is ge­ne­rally poor practice and a taboo in any collaborative project. If you absolutely must overload opera­tors, then only if they behave as expected, follow established semantics and are not surprising. The usu­al behaviour of the +-operator is to return a new object, by value, and leave the operand unaffected. Like so:
std::vector<int> operator+(std::vector<int> v, int n)
{
v.push_back(n);
return v;
}
std::vector's equality comparison performs a lexicographical compare that checks that the size of lhs and rhs are the same, and then compares element by element.
The problem with your code is that you are assigning x+2 to y, and your addition operator is modifying the lhs, acting like a += operator.
Here:
std::vector<int> y = x + 2;
this modifies x, and copy assigns y from x. A well behaved operator+ would be something like
std::vector<int> operator+ ( std::vector<int> v, int val )
{
v.push_back(val);
return v;
}
The confusion arises from the unconventional definition of +. Normally, it would return a modified copy of its argument, leaving the argument itself unchanged. Since the operator acts more like +=, modifying its argument and returning a reference to it, this is roughly equivalent to:
x.push_back(2), x == x
comparing the modified vector to itself.
C++ always compares values, never references; if you want a reference comparison, then you must explicitly compare addresses, &x == &y.
std::vector::operator==() is (usually?) a function, and this is a sequence point in C++03, which means that it needs to fully evaluate all of it's parameters before it can be called.
Both parameters resolve to the same reference (vector x), so it is only natural that it would evaluate to true.
This is because that operator+ never creates a new object, it just modifies one.
It is, in fact, equivalent to this code:
std::vector<int> x;
x.push_back(2);
std::cout << (x==x) << "\n"; // this is no surprise

C++ trying to swap values in a vector

This is my swap function:
template <typename t>
void swap (t& x, t& y)
{
t temp = x;
x = y;
y = temp;
return;
}
And this is my function (on a side note v stores strings) call to swap values but whenever I try to call using values in a vector I get an error. I'm not sure what I'm doing wrong.
swap(v[position], v[nextposition]); //creates errors
I think what you are looking for is iter_swap which you can find also in <algorithm>.
all you need to do is just pass two iterators each pointing at one of the elements you want to exchange.
since you have the position of the two elements, you can do something like this:
// assuming your vector is called v
iter_swap(v.begin() + position, v.begin() + next_position);
// position, next_position are the indices of the elements you want to swap
Both proposed possibilities (std::swap and std::iter_swap) work, they just have a slightly different syntax.
Let's swap a vector's first and second element, v[0] and v[1].
We can swap based on the objects contents:
std::swap(v[0],v[1]);
Or swap based on the underlying iterator:
std::iter_swap(v.begin(),v.begin()+1);
Try it:
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9};
std::vector<int> * v = new std::vector<int>(arr, arr + sizeof(arr) / sizeof(arr[0]));
// put one of the above swap lines here
// ..
for (std::vector<int>::iterator i=v->begin(); i!=v->end(); i++)
std::cout << *i << " ";
std::cout << std::endl;
}
Both times you get the first two elements swapped:
2 1 3 4 5 6 7 8 9
There is a std::swap in <algorithm>
after passing the vector by reference
swap(vector[position],vector[otherPosition]);
will produce the expected result.
Using std::swap by including the <algorithm> library to swap values by references / smart pointers,
e.g. std::swap(v[0], v[1])
Note: v[i] is a reference
Using std::iter_swap from the same library,
e.g. std::iter_swap(v.begin(), v.begin() + v.size() - 1)
Using lvalue references and rvalue tuple by including the <tuple> library
e.g. std::tie(v[0], v[1]) = std::make_tuple(v[1], v[0])
Note: constexpr since C++14