Assume I have a std::vector of double, namely
std::vector<double> MyVec(N);
Where N
is so big that performance matters. Now assume that MyVec
is a nontrivial vector (i.e. it is not a vector of zeros, but has been modified by some routine). Now, I need the negated version of the vector: I need -MyVec
.
So far, I have been implementing it via
std::transform(MyVec.cbegin(),MyVec.cend(),MyVec.begin(),std::negate<double>());
But, really, I do not know if this is something sensible or it is just super naïve from my side.
Am I doing it correctly? Or std::transform is just a super slow routine in this case?
PS: I am using BLAS and LAPACK libraries all the time, but I have not found anything that matches this particular need. However, if there exists such a function in BLAS/LAPACK which is faster than std::transform, I would be glad to know.
The following example shows how to use this method to negate a vector. private Vector negateExample () { Vector vectorResult = new Vector (20, 30); // Make the direction of the Vector opposite but // leave the vector magnitude the same. // vectorResult is equal to (-20, -30) vectorResult.Negate (); return vectorResult; }
The only change in semantics of standard defined methods between the uvector and std::vector are the vector (size_t n) constructor and the resize (size_t n) methods. I found that, if you really are concerned about performance, there might be two more useful operations:
This function is used to negate the given values i.e. to change the sign of the values. It changes the positive values to negative and vice-versa. Note: Objects of this class can be used on standard algorithms such as transform.
This article is about using the std::vector class in the C++ programming language. The std::vector is a useful class for many things. However, when storing integral data types such as an int in a vector, there can be some overhead involved.
#include <vector> #include <algorithm> #include <functional> void check() { std::vector<double> MyVec(255); std::transform(MyVec.cbegin(),MyVec.cend(),MyVec.begin(),std::negate<double>()); }
This code on https://godbolt.org/ with copile option -O3 generate nice assembly
.L3: [...] cmp r8, 254 je .L4 movsd xmm0, QWORD PTR [rdi+2032] xorpd xmm0, XMMWORD PTR .LC0[rip] movsd QWORD PTR [rdi+2032], xmm0 .L4:
It's difficult to imagine faster. Your code is already perfect, don't try to outsmart the compiler and use clean C++ code it works almost every times.
Fortunately the data in std::vector
is contiguous so you can multiply by -1 using vector intrinsics (using unaligned load/stores and special handing of the possible overflow). Or use ippsMulC_64f
/ippsMulC_64f_I
from intel's IPP library (you'll struggle to write something faster) which will use the largest vector registers available to your platform: https://software.intel.com/en-us/ipp-dev-reference-mulc
Update: to clear up some confusion in the comments, the full version of Intel IPP is free (although you can pay for support) and comes on Linux, Windows and macOS.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With