使用模数运算符保持在容器的索引内
Using modulus operator to keep within indices of container
假设我有一个包含m个元素的向量v,以及一个随机访问索引I。
当我增加索引时,如果它超出边界,我想索引第一个(第零)元素。类似地,当我递减索引时,如果索引是<0,我要索引到最后一个元素。目前,我每次只移动一个元素,所以想到了这个函数:
unsigned int GetIndexModM(int index,unsigned int m) {return (index + m) % m;}
调用站点可能看起来像这样:
std::vector<Whatever> v = ... // initialise with 5 elements
unsigned int i = 0;
unsigned int j = GetIndexModM(static_cast<int>(i) - 1,v.size()); // get preceeding index
如果从索引中减去值> m,该函数将失败:
unsigned int j = GetIndexModM(static_cast<int>(i) - 17,v.size()); // oops: returns -2
我的问题:什么是最优雅的实现一个函数,接受任何整数,并返回它的位置作为索引?
处理MOD的技巧是这样的,它适用于正数和负数:
val = ((val % mod_val) + mod_val) % mod_val;
例如,假设我们希望保持值在0到359之间。我们可以这样写:
val = ((val % 360) + 360) % 360;
下面是c++中的一个简单示例:
int getmod(int val, int mod) {
return ((val % mod) + mod) % mod;
}
int main() {
printf("%dn", getmod(50,360)); // prints 50
printf("%dn", getmod(-400,360)); // prints 320
printf("%dn", getmod(350,360)); // prints 350
printf("%dn", getmod(375,360)); // prints 15
printf("%dn", getmod(-725,360)); // prints 355
return 0;
}
遗憾的是,c++没有实现对负整数仍然正确工作的适当模数。
我认为最干净的解决方案确实是使用if
来妥善处理所有情况。这至少使代码明显(因为每个case都是显式),并且更容易找到错误:
unsigned GetIndexModM(int index, unsigned m) {
if (index < 0)
return GetIndexModM(index + m, m);
if (index >= m)
return index % m;
return index;
}
确保index
在[0,n
)中,但只有一个模数运算且没有分支:
index = index % n + (index < 0)*n
其中第一项(包含模数运算符)使值为(-n
, n
),第二项确保值为[0,n
)。
请注意,当n
是无符号类型时,以及在旧版本(11之前)的c++中,%操作符依赖于负参数的实现时,这是不可靠的。
相关文章:
- 重载元组索引运算符-C++
- 重载运算符 [] 用于从对象数组中给出特定索引
- 为什么函数的任何索引处的下标运算符在C++中总是返回1
- std::map 索引运算符与插入方法的性能
- 为什么我不能使用在 Visual C++ 32 位中实现运算符无符号 int() 作为数组索引的类?
- 在对象上运行,运算符重载 () 与索引
- 为什么在C 中使用索引运算符被认为是不好的样式
- String_view的索引运算符([])之间的差异
- c++中线程安全索引运算符的正确方法
- 堆中的对象和重写索引运算符
- 索引运算符的 deques 和超出 deque 大小的问题
- 数组索引运算符重载.现在无法使用比较运算符
- 多次调用索引运算符的性能
- 使用 GDB 的 Python 漂亮打印不支持地图的索引运算符 []
- c++为对象赋值重载数组索引运算符
- 是否重载索引运算符以模拟POD多维数组
- 索引运算符过载
- 重写数组索引运算符
- 自定义索引运算符C++
- 类似 Luabind-syntax(索引运算符)