zoukankan      html  css  js  c++  java
  • 取余操作的原理

    虽然以前学过,但是已经忘了,在返秦的火车上看到如此问题,于是思考了一下。


    C是高级语言,a-(a整除b)*b就不用说了,“整除”是怎么来的?
    但相对于二进制运算,汇编也算一种“高级”语言,那么我问,“div”是怎么来的?

    来看一个例子,如果除数的数是2的幂次的话:

    • 除数2,二进制为0000 0010,被除数5,二进制为0000 0101。除数-1,即此时除数变为0000 0001,两者进行与操作,结果为0000 0001,余数为1。
    • 除数4,二进制为0000 0100,被除数13,二进制为0000 1101。除数-1,即此时除数变为0000 0011,两者进行与操作,结果为0000 0001,余数为1。
    • 除数8,二进制为0000 1000,被除数47,二进制为0010 1111。除数-1,即此时除数变为0000 0111,两者进行与操作,结果为0000 0111,余数为7。

    原理明白了吧,但这种方法仅仅适用于除数为2的幂次数的时候。
    另,这种方法会出现在位图法的位向量操作中,看着是与操作,实际上就是取余。

    #define MAX 1000000  
    #define SHIFT 5  
    #define MASK 0x1F  
    #define DIGITS 32  
      
    int a[1+MAX/DIGITS];
    //置指定位为1
    void setbit(int n) 
    { 
     a[n>>SHIFT] |= (1<<(n&MASK)); 
    }
    //清空指定位                                              
    void clearbit(int n)  
    {  
     a[n>>SHIFT] &= ~(1<<(n&MASK));  
    }
    //检测指定位是否已设置为1    
    int test(int n)  
    {  
        return a[n>>SHIFT] & (1<<(n&MASK)); 
    } 
    

    再次言归正传。
    取余是通过电路进行二进制除法来实现的,简略的原理图(具体的要复杂很多)我记得在数电的教科书上有,改天我查到了补上。
    那么二进制除法是怎样的呢?其实网上一搜一堆原理。(TAT我在高铁上还以为是我自创来着)
    (我们可以直接用减法来实现,但这样的话,如果是10324除以3,就会循环非常多次。)
    针对这种情况,我的想法是:
    1,将除数左移,至与被除数的最高位对齐或者小一位。(小一位是因为待会得用被除数减去左移后的除数,这个时候被除数肯定>(除数*某个2的n次))
    2,被除数减去左移后的除数。
    3,除数左移,这个时候,被除数肯定>(除数*某个2的n1次)
    。。。。
    不停迭代,直至被除数<除数,这个时候被除数就是余数。
    我们先来看不考虑商,仅仅考虑取余

    我们随便找两个数,假设是2381除以7。
    2381,二进制为1001 0100 1101
    7,二进制为111
    用2381的最高位1001减去111,得10。相当于2381-7*256 = 589 (这个缩小得很快的,所以其实除非除数和被除数非常大,或者超出机器位数,每次操作要多读几遍,肯定会有性能损失)

    589 = 刚才的答案10+之前没用过的右边01001101 = 1001001101
    再次重复刚才的过程
    589的最高位1001减去111,得10。相当于589-7*64 = 141

    141 = 刚才的答案10+之前没用过的右边001101 = 10001101
    。。。。。
    如此循环,最后,当被除数剩1时即为余数

    那么商跑到哪里去了呢?
    请看二进制除法原理,原理和我这个是一样的,只不过必须控制移位
    继续用刚才的例子,2381除以7
    以下是不停计算的过程,{}里的是每一次计算的答案,()里的是每一次没参加计算的位

       1001 (0100 1101)             //2381
      -0111                        //7
    --------------------------
      {0010}(0100 1101)          //此时0010>0,所以商的最高位为1
      -0011  1                  //这一次不够减,所以商的次高位为0
    除数继续右移
       0010 01(00 1101)
      -0001 11
    ----------------------------
      {0000 10}(00 1101)   //此时000010>0,所以商的第3高位为1
      -0000 11  1         //此时100减111<0,不够减,所以商的第4高位为0
    


    除数继续右移
    。。。。。。
    如此循环,最后答案为101010100,最前面的1010就是前面四次计算的值。虽然很麻烦,但用电路来实现速度很快。

  • 相关阅读:
    NOIP201208同余方程
    NOIP模拟赛 最佳组合
    NOIP模拟赛 拓展
    CF1253E Antenna Coverage(DP)
    LOJ6033「雅礼集训 2017 Day2」棋盘游戏 (博弈论,二分图,匈牙利算法)
    CF582E Boolean Function(DP,状态压缩,FMT)
    CF750G New Year and Binary Tree Paths(DP)
    Codeforces Round 596 题解
    AGC008E Next or Nextnext(组合计数,神奇思路)
    ARC082E ConvexScore(神奇思路)
  • 原文地址:https://www.cnblogs.com/suprise/p/3086777.html
Copyright © 2011-2022 走看看