识别何时使用取模运算符

71

我知道modulus(%)运算符计算除法的余数。我如何确定需要使用模运算符的情况?

我知道我可以使用模运算符来查看一个数字是偶数还是奇数,是质数还是合数,但仅此而已。我不经常考虑余数。我相信模运算符很有用,我想学会利用它。

我只是有问题识别模运算符适用的地方。在各种编程情况下,我很难看到问题并意识到“嘿!这里可以用除法的余数!”。


基本上,它用于时间、日期和序列重复。 - Daniel Viglione
19个回答

28

想象一下,你有一个已经过去的时间,单位为秒,现在想将其转换为小时、分钟和秒:

h = s / 3600;
m = (s / 60) % 60;
s = s % 60;

21
0 % 3 = 0;
1 % 3 = 1;
2 % 3 = 2;
3 % 3 = 0;

你看到它做了什么吗?在最后一步它回到了零。这可以用于以下情况:

  1. 检查 N 是否可被 M 整除(例如,奇数或偶数)或 N 是否是 M 的倍数。

  2. 设定一个特定值的上限,例如 3。

  3. 获取数字的最后 M 位 -> N % (10^M)。

你能解释一下第三种情况吗?获取一个数字的最后M位 -> N % (10^M)。 - Ka Mok
例如,在一个分给3个人的圣诞降临巧克力日历中,安娜第一天(1)打开日历门窗吃巧克力,本在第二天,卡尔在第三天,然后再由安娜开始,以此类推。使用“day % 3”,当结果为1时是安娜,2时是本,0时是卡尔。这样每个人都可以轻松地获得他们的巧克力,无需大量计算。 - JonyD

18

我将其用于进度条等标记大循环的进度。只有在循环的第n次或count%n == 0时才报告进度。


1
你也是这样吗?这真的会有很大的速度差异。 - Kawa
4
确实是这样。为了得到更快的版本,我喜欢使用位逻辑:count & 0xff == 0(你可以使用0xf或0xff或0xfff等数字,重要的是拥有一个在二进制中是一串连续1的数字)。 - Tobia

12

当我需要限制一个数字为某个倍数时,我会使用它:

temp = x - (x % 10); //Restrict x to being a multiple of 10

2
你能给出一个实际的使用例子吗? - Ka Mok

11
  • 将值包装起来(像时钟一样)。
  • 为对称密钥算法提供有限域。
  • 位运算。

等等。


7

最近我看到的一个使用案例是当您需要反转数字时。例如,将123456变为654321

int number   = 123456;
int reversed = 0;

while ( number > 0 ) {
    # The modulus here retrieves the last digit in the specified number
    # In the first iteration of this loop it's going to be 6, then 5, ...
    # We are multiplying reversed by 10 first, to move the number one decimal place to the left.
    # For example, if we are at the second iteration of this loop, 
    #  reversed gonna be 6, so 6 * 10 + 12345 % 10 => 60 + 5
    reversed = reversed * 10 + number % 10;
    number = number / 10;
}

6

举例来说,您有一个X字节的消息,但在您的协议中,最大大小是Y,而且Y < X。尝试编写一个将消息拆分为数据包的小应用程序,您可能会遇到模数错误问题 :)


5

很多情况下,它是有用的。

如果你需要限制一个数字在某个范围内,可以使用模运算。例如,要生成一个介于0和99之间的随机数,可以这样写:

num = MyRandFunction() % 100;

6
除非100是MyRandFunction()范围的除数,否则会生成不均匀的结果。(想象一下你想要在0 .. RAND_MAX*2/3范围内获取随机数字。) - kennytm
1
@KennyTM:+1。更好的方法可能是能够将100“传递给”MyRandFunction(),这样会更好地处理它。而且,这提供了更好的封装和更松散的耦合。 - Cam
点赞另一个常见用例。(问题不是关于生成加密声音 psrn 的) - danecando

5
任何时候,当您需要除法并希望以除数外的余数表示时,模运算符是适当的。一般情况下,当您想要对余数进行人类可读的操作时,就会想到这个。例如,列出可以放入桶中的物品数量并说“剩余5个”是很好的。
此外,如果您处于可能累积舍入误差的情况下,模除法是很好的选择。例如,如果您经常除以3,则不希望将.33333作为余数传递。传递余数和除数(即分数)是适当的。

5

正如@jweyrich所说,包装值。当我有一个有限的列表并且想要在循环中迭代它时,我发现mod非常方便 - 就像一些UI元素(如图表系列)的固定颜色列表,其中我希望所有系列尽可能不同,但当我用完颜色时,只需从头开始。这也可以与模式一起使用,例如第二次出现红色时,它是虚线; 第三次,点状等 - 但是mod仅用于永远获得红色,绿色,蓝色,红色,绿色,蓝色。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接