C++ 在+;=对于矩阵迭代器(对于数学天才来说可能是一个挑战)

C++ 在+;=对于矩阵迭代器(对于数学天才来说可能是一个挑战),c++,pointers,math,matrix,iterator,C++,Pointers,Math,Matrix,Iterator,我有一个问题,可能还有一个数学挑战。我有一个带有动态数据存储的模板类Matrix(这意味着该类型只有一个模板参数) 我将矩阵数据存储为中的std::vector,并为其编写一个列迭代器,该迭代器将向下一列,从下一列的顶部开始,向下一列,然后继续(行迭代器很简单,因为它只是std::vector的迭代器)。对于随机访问迭代器的递增/递减,我使用私有的advance函数来避免操作符之间的代码重复。看起来是这样的: template<typename T> void Matrix<T

我有一个问题,可能还有一个数学挑战。我有一个带有动态数据存储的模板类
Matrix
(这意味着该类型只有一个模板参数)

我将矩阵数据存储为中的
std::vector
,并为其编写一个列迭代器,该迭代器将向下一列,从下一列的顶部开始,向下一列,然后继续(行迭代器很简单,因为它只是
std::vector
的迭代器)。对于随机访问迭代器的递增/递减,我使用私有的
advance
函数来避免
操作符之间的代码重复。看起来是这样的:

template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) { // defaulted to movement = 1 in header
    _ptr += movement * _shiftFactor;
    if (ge(_ptr, _start + _l)) {
        _currCol++; // increments column count
        _ptr = _start + (_currCol < _shiftFactor ? _currCol : _l); // moves pointer to the top of the column, or to the end if there are no more columns
    }
}
Element: 1 2 3 4
Index:   0 1 2 3
----------------
Element: 5 6 7 8
Index:   4 5 6 7
----------------
Element: 9 1 2 3
Index:   8 9 10 11
----------------
Element: 4 5 6 7
Index:   12 13 14 15
----------------
template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) { // defaulted to movement = 1 in header
    for (std::size_t i = 0; i < std::abs(movement); i++) {
        _ptr += static_cast<int>(std::copysign(1, movement)) * _shiftFactor; // always is either _ptr += _shiftFactor or _ptr += -_shiftFactor
        if (ge(_ptr, _start + _l)) {
            _currCol++;
            _ptr = _start + (_currCol < _shiftFactor ? _currCol : _l);
        } // this conditional is checked every time a row increments
    } // all of this is effectively a movement * _shiftFactor with the if between each increment
}
其中,
Index
是相应元素存储在
std::vector
中的索引。查看我的
advance
函数,我拥有它,因此无论何时调用它(例如

这很好。但是,这是O(
移动),与乘法的O(1)时间相比,即使是这样一个简单的操作,也不能忽略它,这太不令人满意了!!必须有一个更简单的方法来做,对吗

很抱歉我的文章,但我真的很想确保我涵盖了所有内容。我的问题,对你来说可能是数学方面的天才:我如何才能做到这一点O(1)还是在每行增量之间使用if-go时?可能是计算
\u shiftFactor
以上
\u start+\u l
的量级的东西?可能是一些mod magic?帮助


谢谢!

使用建议转换为
行、列
对,增量
,转换回

template<typename T>
auto Matrix<T>::col_iterator::get_index(std::ptrdiff_t offset)
{
    return std::make_pair(offset / n_cols, offset % n_cols); 
}

template<typename T>
auto Matrix<T>::col_iterator::get_offset(std::pair<std::ptrdiff_t, std::ptrdiff_t> index)
{
    return index.first + index.second * n_rows; 
}

template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) 
{
    auto index = get_index(_ptr - _start);

    index.second += movement;
    index.first += (index.second / n_cols); // carry
    index.second %= n_cols; // wrap

    _ptr = get_offset(index) + _start;
}
模板
自动矩阵::列迭代器::获取索引(std::ptrdiff\u t偏移)
{
返回std::make_pair(偏移量/n_列,偏移量%n_列);
}
模板
自动矩阵::列迭代器::获取偏移量(标准::对索引)
{
返回index.first+index.second*n行;
}
模板
无效矩阵::列迭代器::前进(标准::ptrdiff\t移动)
{
自动索引=获取索引(_ptr-_start);
指数。秒+=移动;
index.first+=(index.second/n_cols);//进位
index.second%=n_cols;//换行
_ptr=获取偏移量(索引)+开始;
}

我还找到了一种方法(部分地)借用了与@Evg、@Damien和@Caleth的解决方案相同的逻辑,但将所有内容保持在一个线性索引中。我不知道这是更高效还是更低效,但就是这样

template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) {
    _ptr += movement * _shiftFactor;
    std::ptrdiff_t mag = std::floor((_ptr - (_start + _l)) / static_cast<double>(_shiftFactor));
    std::size_t rows = _l / _shiftFactor;
    if (mag >= 0) {
        _currCol += mag / rows + 1;
        _ptr = _start + (_currCol < _shiftFactor ? _currCol + mag % rows * _shiftFactor: _l);
    }   
}
模板
无效矩阵::列迭代器::前进(标准::ptrdiff\t移动){
_ptr+=移动*\u移位因子;
std::ptrdiff\u t mag=std::floor(_ptr-(_start+_l))/static_cast(_shiftFactor));
std::size\u t rows=\u l/\u shiftFactor;
如果(磁极>=0){
_currCol+=mag/行+1;
_ptr=_start+(_currCol<_shiftFactor?_currCol+mag%行*_shiftFactor:_l);
}   
}
mag
表示高于阈值的幅值)


它适用于
操作符+
和任意
操作符+=
但是不幸的是,它仍然不能与
操作符--
操作符-=
一起工作,因为我设置它的方式(特别是在某些地方
\u start+\u l
需要更改为
\u start
,等等).因此,我产生了一个新问题,如果我能多做一些工作并解决它,我会的,但我还有其他更重要的问题,更多的代码和更少的文本将有助于理解这个问题。我阅读了所有内容,但我没有真正理解你的
操作符+=
实际应该做什么,也没有理解你试图解决的问题solve@user463035818,问题本身很简单:OP想要沿着以行大顺序存储的矩阵列创建迭代器。假设
ptr
指向索引为
ind\u ptr
的元素,那么问题是如何计算
ptr+n
针对任意
n
的元素的索引,taking考虑到一个表示遍历结束的溢出。OP,如果我错了,请纠正我。@Evg-hm好的,我想我知道了,不幸的是我现在必须工作;)@Evg这完全正确。谢天谢地,有人能理解我的晦涩文字@user463035818我添加了更多文本(抱歉)希望这可以澄清一些事情。我喜欢这种带包的东西,它可以避免不必要的线性索引计算作为中间步骤。@Evg最好将这两个函数
get_index
get_offset
作为矩阵类的私有成员函数,然后让迭代器存储指向矩阵的指针,还是将其保留在迭代器中?因为我在Matrix类中已经有了返回代理的
操作符[]
,所以我可以模拟
操作符[][]
@jonathanley,如果它们也在
Matrix
类中使用,我可能会将它们移到那里。迭代器是否应该存储指向
矩阵的指针,而不是它的一些成员的副本,这是有争议的。如果存在间接操作,优化器可能无法生成好的代码。如果您想要快速迭代器,您应该通过查看汇编代码和测量性能来比较不同的方法。如果您决定在迭代器中保留<代码> nyReals> />代码> No.CysN/Culs>代码,请考虑第三个选项——使这些函数成为自由函数(可能在一些内部<代码>命名空间< /代码>)。
template<typename T>
auto Matrix<T>::col_iterator::get_index(std::ptrdiff_t offset)
{
    return std::make_pair(offset / n_cols, offset % n_cols); 
}

template<typename T>
auto Matrix<T>::col_iterator::get_offset(std::pair<std::ptrdiff_t, std::ptrdiff_t> index)
{
    return index.first + index.second * n_rows; 
}

template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) 
{
    auto index = get_index(_ptr - _start);

    index.second += movement;
    index.first += (index.second / n_cols); // carry
    index.second %= n_cols; // wrap

    _ptr = get_offset(index) + _start;
}
template<typename T>
void Matrix<T>::col_iterator::advance(std::ptrdiff_t movement) {
    _ptr += movement * _shiftFactor;
    std::ptrdiff_t mag = std::floor((_ptr - (_start + _l)) / static_cast<double>(_shiftFactor));
    std::size_t rows = _l / _shiftFactor;
    if (mag >= 0) {
        _currCol += mag / rows + 1;
        _ptr = _start + (_currCol < _shiftFactor ? _currCol + mag % rows * _shiftFactor: _l);
    }   
}