Eigen,如何处理按元素除以零
Eigen, How to handle element-wise division by zero
如果某个分隔符可能为 0,如何处理 Eigen 中的逐元素除法?
我希望结果为 0。
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
ArrayXd a(3), b(3), c;
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
c = b / a;
}
我使用 binaryExpr 找到了这个解决方案,但不确定它是否有效。需要测试速度。我有数以万计的值要计算。
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
template<typename Scalar>
struct SecureDivisionOp {
SecureDivisionOp(Scalar v_ = 0) { v = v_; }
Scalar v;
Scalar operator()(const Scalar& a, const Scalar& b) const {
return b==0 ? v : a/b;
}
};
int main()
{
ArrayXd a(3), b(3), c;
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
c = b.binaryExpr(a, SecureDivisionOp<double>(0));
std::cout << c << std::endl;
}
您可以使用 binaryExpr 处理被零除:
ArrayXd a(3), b(3);
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
Eigen::ArrayXd c = a.binaryExpr(b, [](auto x, auto y) { return y==0 ? 0 : x/y; });
如果你的编译器在 auto-vectorization 方面相当不错,你可以使用 Eigen 的 .select( )
机制:
c = (a!=0).select(b/a, 0.0);
Clang 6 或更新版本(带有 -O3 -DNDEBUG -march=skylake
)将把它的 main-loop 编译成等同于:
vmovupd ymm1, ymmword ptr [rax]
vcmpneqpd ymm2, ymm1, ymm0
vmaskmovpd ymm3, ymm2, ymmword ptr [rdx]
vdivpd ymm1, ymm3, ymm1
vandpd ymm1, ymm2, ymm1
vmovupd ymmword ptr [rax], ymm1
唯一轻微的性能改进是避免 vmaskmovpd
——但从编译器的角度来看这是必要的,因为严格来说,并不是每个 i
都读取 b[i]
其中 a[i]==0
.
如果某个分隔符可能为 0,如何处理 Eigen 中的逐元素除法?
我希望结果为 0。
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
ArrayXd a(3), b(3), c;
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
c = b / a;
}
我使用 binaryExpr 找到了这个解决方案,但不确定它是否有效。需要测试速度。我有数以万计的值要计算。
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
template<typename Scalar>
struct SecureDivisionOp {
SecureDivisionOp(Scalar v_ = 0) { v = v_; }
Scalar v;
Scalar operator()(const Scalar& a, const Scalar& b) const {
return b==0 ? v : a/b;
}
};
int main()
{
ArrayXd a(3), b(3), c;
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
c = b.binaryExpr(a, SecureDivisionOp<double>(0));
std::cout << c << std::endl;
}
您可以使用 binaryExpr 处理被零除:
ArrayXd a(3), b(3);
a << 1, 2, 0;
b << 1.2, 3.4, 5.6;
Eigen::ArrayXd c = a.binaryExpr(b, [](auto x, auto y) { return y==0 ? 0 : x/y; });
如果你的编译器在 auto-vectorization 方面相当不错,你可以使用 Eigen 的 .select( )
机制:
c = (a!=0).select(b/a, 0.0);
Clang 6 或更新版本(带有 -O3 -DNDEBUG -march=skylake
)将把它的 main-loop 编译成等同于:
vmovupd ymm1, ymmword ptr [rax]
vcmpneqpd ymm2, ymm1, ymm0
vmaskmovpd ymm3, ymm2, ymmword ptr [rdx]
vdivpd ymm1, ymm3, ymm1
vandpd ymm1, ymm2, ymm1
vmovupd ymmword ptr [rax], ymm1
唯一轻微的性能改进是避免 vmaskmovpd
——但从编译器的角度来看这是必要的,因为严格来说,并不是每个 i
都读取 b[i]
其中 a[i]==0
.