21

可能重复:
负数模式正在融化我的大脑!

我想知道我正在尝试做的事情是否有更好的算法:

wrapIndex(-6, 3) = 0
wrapIndex(-5, 3) = 1
wrapIndex(-4, 3) = 2
wrapIndex(-3, 3) = 0
wrapIndex(-2, 3) = 1
wrapIndex(-1, 3) = 2
wrapIndex(0, 3) = 0
wrapIndex(1, 3) = 1
wrapIndex(2, 3) = 2
wrapIndex(3, 3) = 0
wrapIndex(4, 3) = 1
wrapIndex(5, 3) = 2

我想出了

函数 wrapIndex(i, i_max) {
        如果(我 > -1)
            返回 i%i_max;

        变量 x = i_max + i%i_max;
        如果(x == i_max)
            返回0;

        返回 x;
    }

有没有更好的方法来做到这一点?

4

5 回答 5

28

此解决方案是无分支的,但执行%两次:

function wrapIndex(i, i_max) {
   return ((i % i_max) + i_max) % i_max;
}

应该说 C#/Java 的行为是假定的,即结果与除数%具有相同的符号。一些语言将余数计算定义为取除数的符号(例如在 Clojure 中)。有些语言有两种变体(Common Lisp、Haskell 等中的/对)。Algol-68总是返回一个非负数。C++ 将其留给实现直到 C++11,现在余数的符号(几乎)完全根据被除数指定modmodrem%x

也可以看看

于 2010-08-05T17:07:27.690 回答
10

具有两个%操作的解决方案有效,但在大多数硬件上的大多数语言中这有点快(但是也有例外):

int wrapIndex(int i, int i_max) {
    i = i%i_max;
    return i<0 ? i+i_max : i;
}
于 2010-08-05T17:17:18.030 回答
5

更好是一个品味问题,但是怎么样

var x = (i_max + i % i_max) % i_max;
于 2010-08-05T17:05:25.900 回答
2

你可以这样做:

function wrapIndex(i, i_max) {
    if (i < 0) i = (i % i_max) + i_max;
    return i % i_max;
}
于 2010-08-05T17:03:35.123 回答
2

许多用户给出了很好的答案,只是要注意负数,因为不同的语言可能表现不同。例如,这个 C 代码片段写“-1”

int main ()
{
    printf("%d\n", (-4) % 3);
}

在 python 中,我们有不同的输出值

Python 2.6.4 (r264:75706, Dec  7 2009, 18:43:55) 
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (-4) % 3
2

编辑:其实我不认为你会有负指数!不过很高兴知道这一点。

于 2010-08-05T17:50:47.447 回答