Ключ к ответу на этот вопрос: когда косвенное указание быстрее арифметического? Ответ почти никогда. Обходы по порядку могут быть примерно такими же быстрыми для 2D, и от этого дела идут хуже:
2D random access
Array of Arrays - 600 M / second
Multiplication - 1.1 G / second
3D in-order
Array of Array of Arrays - 2.4G / second
Multiplication - 2.8 G / second
(etc.)
Так что тебе лучше просто делать математику.
Теперь вопрос в том, как сделать нарезку. Первоначально, если у вас есть измерения n1, n2, n3, ... и индексы i1, i2, i3, ..., вы вычисляете смещение в массиве
i = i1 + n1*(i2 + n2*(i3 + ... ))
, где обычно i1
выбирается как последнее (самое внутреннее) измерение (но в целом это должно быть измерение чаще всего в самом внутреннем цикле). То есть, если бы это был массив массивов (...), вы бы указали в нем как a(...)(i3)(i2)(i1)
.
Теперь предположим, что вы хотите нарезать это. Во-первых, вы можете задать смещение o1, o2, o3 для каждого индекса:
i = (i1 + o1) + n1*((i2 + o2) + n2*((i3 + o3) + ...))
и тогда у вас будет более короткий диапазон для каждого (назовем это m1, m2, m3, ...).
Наконец, если вы полностью исключите измерение - скажем, например, что m2 == 1
, то есть i2 == 0
, вы просто упростите формулу:
i = (i1 + o1 + n1*o2) + (n1+n2)*((i3 + o3) + ... ))
Я оставлю это в качестве упражнения для читателя, чтобы выяснить, как это сделать в целом, но учтите, что мы можем хранить новые константы o1 + n1*o21
и n1+n2
, поэтому нам не нужно продолжать делать эту математику ломтик.
Наконец, если вы разрешаете произвольные измерения, вы просто помещаете эту математику в цикл while. По общему признанию, это немного замедляет его, но вы по крайней мере так же хороши, как если бы вы использовали разыменование указателя (почти в каждом случае).