【问题标题】:Recognizing when to use the modulus operator识别何时使用模运算符
【发布时间】:2011-02-06 05:58:34
【问题描述】:

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

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

我只是在确定模运算符适用的位置时遇到问题。在各种编程情况下,我很难看到问题并意识到“嘿!除法的其余部分可以在这里工作!”。

【问题讨论】:

  • 本质上是用于时间、日期和顺序的重复

标签: operators modulo


【解决方案1】:

通常,在循环中,您希望每第 k 次迭代执行一次操作,其中 k 是 0

所以,你会做这样的事情:

int k = 5;
int n = 50;
for(int i = 0;i < n;++i)
{
    if(i % k == 0)  // true at 0, 5, 10, 15..
    {
        // do something
    }
}

或者,您想将某些内容保持在一定范围内。请记住,当您使用任意数字 mod 某物时,它必须产生一个介于 0 和该数字 - 1 之间的值。

【讨论】:

    【解决方案2】:

    我见过的模数运算符的最佳用途是检查我们拥有的数组是否是原始数组的旋转版本。

    A = [1,2,3,4,5,6] B = [5,6,1,2,3,4]

    现在如何检查 B 是否是 A 的旋转版本?

    第 1 步:如果 A 的长度与 B 的长度不同,那么它肯定不是旋转版本。

    第 2 步:检查 A 的第一个元素在 B 中的索引。这里 A 的第一个元素是 1。它在 B 中的索引是 2(假设您的编程语言具有从零开始的索引)。 让我们将该索引存储在变量“Key”中

    第 3 步:现在如何检查 B 是否是 A 的旋转版本??

    这就是模数函数发挥作用的地方:

    for (int i = 0; i< A.length; i++)
    {
    
    // here modulus function would check the proper order. Key here is 2 which we recieved from Step 2
       int j = [Key+i]%A.length;
    
       if (A[i] != B[j])
       {
         return false;
       }
    }
    
    return true;
    

    【讨论】:

      【解决方案3】:

      我最近看到的一个用例是当您需要反转一个数字时。例如,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;
      }
      

      【讨论】:

        【解决方案4】:

        这是判断一个数字是偶数还是奇数的简单方法。就做#mod 2,如果是0就是偶数,1就是奇数。

        【讨论】:

          【解决方案5】:

          我最喜欢的用途是迭代。

          假设您有一个计数器正在递增,然后想从已知列表中获取相应的项目,但您只有 n 项目可供选择,并且您想重复一个循环。

          var indexFromB = (counter-1)%n+1;

          n=3 给出的结果 (counter=indexFromB):

          `1=1`
          `2=2`
          `3=3`
          `4=1`
          `5=2`
          `6=3`
          ...
          

          【讨论】:

            【解决方案6】:
            • 计算最大公约数
            • 判断一个数是否为回文数
            • 判断一个数是否只包含...
            • 确定一个数字由多少...组成...

            【讨论】:

              【解决方案7】:

              将线性数据结构转换为矩阵结构: 其中a 是线性数据的索引,b 是每行的项目数:

              row = a/b
              column = a mod b
              

              注意上面是简化的逻辑:a 除法前必须偏移-1,结果必须归一化+1。

              示例:(3 行,每行 4 行)

              1  2  3  4    
              5  6  7  8    
              9 10 11 12 
              
              (7 - 1)/4 + 1 = 2
              
              7 is in row 2
              
              (7 - 1) mod 4 + 1 = 3 
              
              7 is in column 3
              

              模数的另一个常见用途:按位散列一个数字。假设您想将年份和月份存储在六位数字 195810 中。month = 195810 mod 100 从右数第三个所有数字都可以被 100 整除,因此在这种情况下,余数是最右边的 2 个数字,月份是 10。要提取年份 195810 / 100产生 1958 年。

              【讨论】:

              • 为什么必须偏移 1?
              【解决方案8】:

              模数可用于将总分钟转换和拆分为“小时和分钟”:

              小时 = 分钟 / 60

              minutes_left = 分钟 % 60

              在小时位中,我们需要去掉小数部分,这取决于您使用的语言。

              然后我们可以相应地重新排列输出。

              【讨论】:

              • 我们还可以使用模数来判断一年是否是闰年,因为它可以被 4 整除。JS 中的示例: if (year % 4 === 0) { // 这是闰年年 }。 (注意:更准确的检查还将验证可被 100 和 400 整除)
              【解决方案9】:

              如果出于某种疯狂的原因需要进行整数除法并得到小数,并且您无法将整数转换为支持小数除法的数字,或者如果您需要返回小数,则模数也非常有用小数。

              我将使用% 作为模运算符

              例如

              2/4 = 0

              在哪里做这个

              2/4 = 0 and 2 % 4 = 2

              所以你真的很疯狂,假设你想让用户输入一个分子和一个除数,然后将结果显示为一个整数,然后是一个小数。

              whole Number = numerator/divisor
              fractionNumerator = numerator % divisor
              fractionDenominator = divisor
              

              模除法有用的另一种情况是,如果您正在增加或减少一个数字,并且您希望将数字包含在某个数字范围内,但是当您到达顶部或底部时,您不想停下来.您想分别循环到列表的底部或顶部。

              想象一个循环遍历数组的函数。

              Function increase Or Decrease(variable As Integer) As Void
                  n = (n + variable) % (listString.maxIndex + 1)  
                  Print listString[n]
              End Function
              

              之所以 n = (n + variable) % (listString.maxIndex + 1) 是为了考虑到最大索引。

              这些只是我在对桌面应用程序以及机器人和模拟环境的编程中不得不使用模数的一些事情。

              【讨论】:

                【解决方案10】:
                0 % 3 = 0;
                1 % 3 = 1;
                2 % 3 = 2;
                3 % 3 = 0;
                

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

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

                2. 设置一个特定值的上限。在这种情况下 3.

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

                【讨论】:

                • 你能解释一下情况3吗?获取数字的最后 M 位 -> N % (10^M)。
                • 例如,在一个Advent calendar chocolate 中,就是除以3 人。 Anna 在第一天 (1) 打开日历门/窗并吃巧克力,Ben 在第 2 天,Carl 在第 3 天,然后是 Anna,以此类推。制作“day % 3”,当结果为 1:Anna,2:Ben,0:Carl。每个人都无需大量计算即可获得巧克力。
                【解决方案11】:

                正如@jweyrich 所说,包装值。当我有一个有限列表并且我想在循环中迭代它时,我发现 mod 非常方便 - 就像一些 UI 元素的固定颜色列表,比如图表系列,我希望所有系列都不同,可能的程度,但是当我用完颜色时,就从头开始。这也可以与图案一起使用,这样第二次出现红色时,它就会变成虚线;第三次,点,等等 - 但 mod 只是用来得到红色,绿色,蓝色,红色,绿色,蓝色,永远。

                【讨论】:

                  【解决方案12】:

                  我将它用于进度条等标记通过大循环的进度。仅在循环中每 n 次或 count%n == 0 时报告进度。

                  【讨论】:

                  • 你也是?这确实会产生很大的速度差异。
                  • 确实如此。对于更快的版本,我喜欢使用位逻辑:count &amp; 0xff == 0(您可以使用 0xf 或 0xff 或 0xfff 等:关键是有一个二进制数字是实心的 1 字符串)
                  【解决方案13】:
                  • 包装值(如时钟)。
                  • 为对称密钥算法提供有限域。
                  • 按位运算。

                  等等。

                  【讨论】:

                    【解决方案14】:

                    任何时候你有除法并且想要以十进制以外的形式表示余数时,mod 运算符都是合适的。想到的事情通常是当你想用剩下的东西做一些人类可读的事情时。列出您可以放入桶中的物品数量并说“剩下 5 个”很好。

                    此外,如果您遇到可能会产生舍入误差的情况,则模除法是很好的选择。例如,如果您经常除以 3,您不想将 .33333 作为余数传递。通过余数和除数(即分数)是合适的。

                    【讨论】:

                      【解决方案15】:

                      我在将数字限制为某个倍数时使用过它:

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

                      【讨论】:

                      • 你能给出这个的实际用法吗?
                      【解决方案16】:

                      假设您有一个以秒为单位的经过时间,并且您想将其转换为小时、分钟和秒:

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

                      【讨论】:

                        【解决方案17】:

                        素数的计算

                        【讨论】:

                        • 虽然我还没有真正找到真正需要计算它们的情况。
                        • 素数因此模在经典密码学中被大量使用
                        【解决方案18】:

                        在很多情况下它很有用。

                        如果您需要将数字限制在一定范围内,您可以使用 mod。例如,要生成一个 0 到 99 之间的随机数,您可能会说:

                        num = MyRandFunction() % 100;
                        

                        【讨论】:

                        • -1。这将产生不一致的结果,除非 100 是MyRandFunction() 范围的除数。 (假设你想要一个随机数在0 .. RAND_MAX*2/3。)
                        • @KennyTM:+1。可能更好的是能够将 100 into MyRandFunction() 正确处理。另外,它提供了更好的封装和更松散的耦合。
                        • 赞成另一个常见用例。 (问题不在于生成加密声音 psrn)
                        【解决方案19】:

                        示例。您有 X 字节的消息,但在您的协议中,最大大小是 Y 并且 Y

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2020-11-01
                          • 1970-01-01
                          • 2015-11-08
                          • 2015-02-16
                          • 1970-01-01
                          • 2022-12-16
                          • 2017-09-28
                          • 1970-01-01
                          相关资源
                          最近更新 更多