这将是一个很长的问题,请在阅读前深吸一口气。
我想了解将一维数组的索引转换为多维数组的向量索引的最快算法。
让我们继续举例说明我为什么需要它:
我有一个二维数组:Array [i1] [i2]
i1从i1_b = 0运行到i1_e = 2
i2从i2_b = 0运行到i2_e = 1
所以这个数组逐行输出到文件中:
数组[0] [0]
数组[0] [1]
数组[0] [2]
数组[1] [0]
数组[1] [1]
数组[1] [2]
现在我逐行读取文件,索引k是最后读取的行号。
我读取了第一行,即Array [0] [0]和k = 0
我读了第二行,即Array [0] [1]和k = 1
...
可以注意到k将从k_b = 0到k_e = 5和
运行k = 0将对应于i1 = 0,i2 = 0
k = 1将对应于i1 = 0,i2 = 1
...
问题:所以我的问题是如何以最快的方式将k转换为i1和i2? (我在阅读文件时不需要它,但稍后在我的程序中)
在此示例中,其中一个解决方案是
i1 = k /(i1_e - i1_b + 1);
i2 = k%(i1_e - i1_b + 1);
问题1:就周期和计算机时间而言,它是否是最快的解决方案?
行。 问题2:我们如何将此算法推广到多维数组?
数组[I1] [12] [i3的] [6-14]
i1 = k /(i1_e - i1_b + 1);
i2 = k%(i1_e - i1_b + 1);
i3 = i2 /(i1_e - i1_b + 1);
i4 = i2%(i1_e - i1_b + 1);
问题3:这是最快的方式吗?
问题4:相关问题是模块化除法,整数除法,加整数和乘法整数的延迟是多少?如果这些数字取决于架构,请告诉我。
提前致谢!
P.S。 有人可能更容易将此问题视为将秒转换为几小时 - 分钟 - 秒的最快算法。
答案 0 :(得分:6)
问题2:我们如何将此算法推广到多维数组?
如果您有一个数组arr[dim_1][dim_2]...[dim_n]
,则可以使用等式
k = i_1*(dim_2*...*dim_n) + i_2*(dim_3*...*dim_n) + ... + i_{n-1}*dim_n + i_n
= i_1*(dim_2*...*dim_n) + r_2
所以i_1 = k / (dim_2*..*dim_n)
和r_2 = k % (dim_2*...*dim_n)
,然后
i_2 = r_2 / (dim_3*...*dim_n) and r_3 = r_2 % (dim_3*...*dim_n)
等
i_j = r_j / (dim_{j+1}*...*dim_n) and r_{j+1} = r_j % (dim_{j+1}*...*dim_n)
直到找到i_n = r_n
。
问题3:这是最快的方式吗?
如果在编译时已知尺寸,则可以通过乘法,移位和加法/减法来替换除法。在许多架构中,这比分区指令更快。在其他人身上,不是。
但是,如果你在该数组中进行很多索引,那么这是值得思考的。
问题4:相关问题是模块化除法,整数除法,加整数和乘法整数的延迟是多少?如果这些数字取决于架构,请告诉我。
这些数字取决于架构和处理器。
答案 1 :(得分:0)
请在下面找到我将如何在C ++ 1x中实现它,我希望这可能有用。 干杯
#include <iostream>
#include <array>
#include <algorithm>
/* stream arrays element by element to ostream */
template<size_t N, typename T>
std::ostream& operator<<(std::ostream& os, std::array<T, N> const& obj)
{
os << "{ ";
for(auto a:obj)std::cout << a << " ";
std::cout << "}";
return os;
}
//end of recursion
template<size_t DIM, size_t I>
constexpr typename std::enable_if< (I==DIM), void >::type
get_indexes(unsigned int index, std::array<unsigned int, DIM> const& depths, std::array<unsigned int,DIM>& indexes)
{}
//begin of the recursion
template<size_t DIM, size_t I=0>
constexpr typename std::enable_if< (I<DIM), void >::type
get_indexes(unsigned int index, std::array<unsigned int, DIM> const& depths, std::array<unsigned int,DIM>& indexes)
{
unsigned int factor = 1;
for(unsigned int i=I+1; i<DIM; i++) factor *=depths[i];
indexes[I] = index/factor;
unsigned int next_index = index%factor;
get_indexes<DIM, I+1>(next_index, depths, indexes );
}
//some testing with 3 dimensions
int main()
{
constexpr unsigned ndimensions=3;
std::array<unsigned int, ndimensions> depths{2, 3, 4};
unsigned int nboxes = 1;
for(unsigned int i =0; i< ndimensions; i++)nboxes *=depths[i];
std::array<unsigned int, ndimensions> indexes;
for(size_t i=0; i<nboxes; i++)
{
get_indexes<ndimensions>(i,depths , indexes);
std::cout << i << " -> " <<indexes<< std::endl;
}
return 0;
}