Самый короткий способ написать то, что вы хотите, это
void foo(Eigen::VectorXf& inout, float threshold)
{
inout = (threshold < inout.array().abs()).select(inout, 0.0f);
}
Однако ни сравнения, ни метод select
не векторизованы Eigen ( на данный момент ).
Если скорость важна, вам нужно либо написать некоторый код SIMD вручную, либо написать собственный функтор, который поддерживает метод packet
(он использует внутреннюю функциональность Eigen, поэтому он не гарантированно стабилен!):
template<typename Scalar> struct threshold_op {
Scalar threshold;
threshold_op(const Scalar& value) : threshold(value) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const{
return threshold < std::abs(a) ? a : Scalar(0); }
template<typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const {
using namespace Eigen::internal;
return pand(pcmp_lt(pset1<Packet>(threshold),pabs(a)), a);
}
};
namespace Eigen { namespace internal {
template<typename Scalar>
struct functor_traits<threshold_op<Scalar> >
{ enum {
Cost = 3*NumTraits<Scalar>::AddCost,
PacketAccess = packet_traits<Scalar>::HasAbs };
};
}}
Затем его можно передать в unaryExpr
:
inout = inout.unaryExpr(threshold_op<float>(threshold));
Godbolt-Demo ( должен работать с SSE / AVX / AVX512 / NEON /)...): https://godbolt.org/z/bslATI
Фактически единственной причиной замедления могут быть субнормальные числа.В этом случае простой
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
должен добиться цели (ср: Почему изменение от 0,1f до 0 замедляет производительность в 10 раз? )