如何在两个Boost::MULTI_ARRAYS(C++)之间执行数学运算?
如何在两个Boost::MULTI_ARRAYS之间执行数学运算?
值类型为DOUBLE的两个数组相加的示例:
auto array1 = boost::multi_array<double, 2>(boost::extents[10][10]);
auto array2 = boost::multi_array<double, 2>(boost::extents[10][10]);
auto array3 = array1 + array2; //Does not compile
我知道的一种可能性是英特尔IPP库。例如,可以用ippiAdd_
来完成两个矩阵的相加。但遗憾的是,英特尔IPP不支持双精度加法。
那么,有没有人知道除了英特尔IPP之外的另一个库,一个克服英特尔IPP中限制值类型缺点的解决方案?
解决方案
您可以&只写它:
namespace ArrayOperators {
template <typename L, typename R>
static inline auto operator+(L const& l, R const& r) {
return ArrayOp {std::plus<>{}} (l, r); }
template <typename L, typename R>
static inline auto operator-(L const& l, R const& r) {
return ArrayOp {std::minus<>{}} (l, r); }
template <typename L, typename R>
static inline auto operator/(L const& l, R const& r) {
return ArrayOp {std::divides<>{}} (l, r); }
template <typename L, typename R>
static inline auto operator*(L const& l, R const& r) {
return ArrayOp {std::multiplies<>{}} (l, r); }
}
当然,这需要我们实际实现ArrayOp
可调用的。我冒昧地去
- 实现异构数组(所以当左右手的元素类型不同时)
- 在右侧不是数组的情况下实现它,在这种情况下,标量操作数将应用于左侧的每个元素
- 我不支持
- 就地作业
- 数组引用/数组(常量)视图
- 不同形状或维度的数组
这里:
template <typename Op> struct ArrayOp {
Op op;
explicit ArrayOp(Op op) : op(op) {}
template <typename T, typename Scalar, size_t Dim> auto operator()(
boost::multi_array<T, Dim> const& l,
Scalar const& v) const
{
std::array<int, Dim> shape;
std::copy_n(l.shape(), Dim, shape.data());
using R = boost::multi_array<decltype(op(T{}, v)), Dim>;
R result(shape);
std::transform(
l.data(), l.data()+l.num_elements(),
result.data(),
[&op=op,v](auto const& el) { return op(el, v); });
return result;
}
template <typename T, typename U, size_t Dim> auto operator()(
boost::multi_array<T, Dim> const& l,
boost::multi_array<U, Dim> const& r) const
{
std::array<int, Dim> shape;
std::copy_n(l.shape(), Dim, shape.data());
assert(std::equal(shape.begin(), shape.end(), r.shape()));
using R = boost::multi_array<decltype(op(T{}, U{})), Dim>;
R result(shape);
std::transform(
l.data(), l.data()+l.num_elements(),
r.data(), result.data(),
[&op=op](auto const& v1, auto const& v2) { return op(v1, v2); });
return result;
}
};
基本上归结为
- 推断结果数组元素类型和形状
- 执行一元或二进制转换(取决于标量/数组RHS)
现在我们可以编写程序了:
Live On Compiler Explorer
int main() {
using MA = boost::multi_array<int, 2>;
auto shape = boost::extents[3][3];
MA array1(shape), array2(shape);
std::generate_n(array1.data(), array1.num_elements(),
[n = 0]() mutable { return n+=100; });
std::generate_n(array2.data(), array2.num_elements(),
[n = 0]() mutable { return n+=1; });
fmt::print("array1:
{}
", fmt::join(array1,"
"));
fmt::print("array2:
{}
", fmt::join(array2,"
"));
using namespace ArrayOperators;
auto array3 = (array1 + array2)/100.0;
fmt::print("array3:
{}
", fmt::join(array3,"
"));
}
并打印
array1:
{100, 200, 300}
{400, 500, 600}
{700, 800, 900}
array2:
{1, 2, 3}
{4, 5, 6}
{7, 8, 9}
array3:
{1.01, 2.02, 3.03}
{4.04, 5.05, 6.06}
{7.07, 8.08, 9.09}
但请稍等,您正在解决什么问题
- 如果需要矩阵(不是数组)操作,请使用Boost uBlas、Eigen、Armadillo
- 如果您想获得最佳性能,可以使用SIMD/AVX2/GPU指令,您可以使用Boost Compute
相关文章