C++中多维数组的索引转换

fiei3ece  于 2022-12-20  发布在  其他
关注(0)|答案(1)|浏览(151)

我有转换3D坐标到id(索引)和反向的示例代码。我怎么能为N维(例如5D和6D)数组做到这一点?这里是3D转换代码:

inline NoximCoord id2Coord(int id) {
  NoximCoord coord;

  coord.z = id / (NoximGlobalParams::mesh_dim_x *
                  NoximGlobalParams::mesh_dim_y);  ////
  coord.y = (id - coord.z * NoximGlobalParams::mesh_dim_x *
                      NoximGlobalParams::mesh_dim_y) /
            NoximGlobalParams::mesh_dim_x;
  coord.x = (id - coord.z * NoximGlobalParams::mesh_dim_x *
                      NoximGlobalParams::mesh_dim_y) %
            NoximGlobalParams::mesh_dim_x;

  assert(coord.x < NoximGlobalParams::mesh_dim_x);
  assert(coord.y < NoximGlobalParams::mesh_dim_y);
  assert(coord.z < NoximGlobalParams::mesh_dim_z);

  return coord;
}

inline int coord2Id(const NoximCoord &coord) {
  int id =
      coord.z * NoximGlobalParams::mesh_dim_x * NoximGlobalParams::mesh_dim_y +
      (coord.y * NoximGlobalParams::mesh_dim_x) + coord.x;
  assert(id < NoximGlobalParams::mesh_dim_x * NoximGlobalParams::mesh_dim_y *
                  NoximGlobalParams::mesh_dim_z);
  return id;
}

我需要以这种方式转换(c++〈14),而不是在其他答案上实现的方式。

6l7fqoea

6l7fqoea1#

好吧,据我所知,这是相当标准的。坐标到ID的转换是一个简单的多项式计算,最好使用Horner's method来计算。逆函数看起来比实际需要的更混乱,因为你在使用模或手动计算它时不一致。
这个版本使用std::arrays作为维度,从最里面的维度到最外面的维度,所以{x, y, z, ...}

#include <array>
#include <functional>
// using std::multiplies
#include <numeric>
// using std::partial_sum

template<std::size_t N>
int coord2Id(const std::array<int, N>& coords,
             const std::array<int, N>& mesh) noexcept
{
    int id = coords.back();
    for(std::size_t i = N - 1; i > 0; --i)
        id = id * mesh[i - 1] + coords[i - 1];
    return id;
}

template<std::size_t N>
std::array<int, N> id2Coord(int id, const std::array<int, N>& mesh) noexcept
{
    std::array<int, N> coord;
    std::array<int, N-1> partials;
    std::partial_sum(mesh.begin(), mesh.end() - 1, partials.begin(),
                     std::multiplies<int>{});
    for(std::size_t i = N - 1; i > 0; --i) {
        coord[i] = id / partials[i - 1];
        id = id % partials[i - 1];
    }
    coord.front() = id;
    return coord;
}

提醒你一句:对于较大的尺寸,ID很容易溢出整数范围,例如{500, 500, 500, 500}网格已经太大了。我建议改用std::ptrdiff_t
下面是从原始图案的快速转换:

class NoximCoord
{
public:
    int x, y, z;
};
struct NoximGlobalParams
{
    static int mesh_dim_x, mesh_dim_y, mesh_dim_z;
};
int coord2Id(const NoximCoord& coord) noexcept
{
    return coord2Id(std::array<int, 3>{{coord.x, coord.y, coord.z}},
        std::array<int, 3>{{NoximGlobalParams::mesh_dim_x,
                            NoximGlobalParams::mesh_dim_y,
                            NoximGlobalParams::mesh_dim_z}});
}
NoximCoord id2Coord(int id) noexcept
{
    std::array<int, 3> coords = id2Coord(
        id, std::array<int, 3>{{NoximGlobalParams::mesh_dim_x,
                                NoximGlobalParams::mesh_dim_y,
                                NoximGlobalParams::mesh_dim_z}});
    return NoximCoord{coords[0], coords[1], coords[2]};
}

相关问题