<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      用位運(yùn)算實(shí)現(xiàn)加減乘除(2)

      位運(yùn)算實(shí)現(xiàn)除法

      先說一種普遍的除法,比如下圖中的a / b:

      b向左移到最接近a的時(shí)候,但是又沒a大,要保證左移到最接近a但是不比a大。
      除的最終結(jié)果里,這個(gè)位置一定有1,見下圖:

      然后把a(bǔ)減掉這個(gè)數(shù),變成:

      然后再把b移動(dòng)到最接近a的時(shí)候,這個(gè)位置一定是1:

      這就是最終的結(jié)果:

       

      a/b的過程就是上面的。如果不太好理解的話,看下面這種解釋:
      如果a / b = c,如圖:
      說明啥?a可以這么表示:

      再舉個(gè)例子:

      看到上面的例子,那我們應(yīng)該怎么做?
      怎么求這個(gè)c呢?這么想:
      a - 一個(gè)盡可能大的2某次方 * b = a'
      a' - 一個(gè)盡可能大的2某次方 * b = a''
      a'' - 一個(gè)盡可能大的2某次方 * b = a'''
      ...
      一直這么減,就把結(jié)果得到了。

       

      b*c的演算過程:

      a = b * 2 + b * 22,也就是 a = b << 1 + b << 2

       

      假設(shè),a = b*2? + b*2? + b*23,你說c是啥?在第7、5、3位置上是1,其他都是0 :

      所以,怎么算a/b呢?
      a我先看看,最大的2的某次方 * b,而且2?*b不能超過a,找到最大2的某次方。假設(shè)是7,那么我就知道最終結(jié)果7的位置上一定是1。
      a': a - b*2?,再次找到最接近a'的2某次方 * b,假設(shè)是5,那么我知道最終結(jié)果5的位置上一定是1。
      a'': a' - b*2?, 再次找到最接近a''的2某次方 * b,假設(shè)是3,那么我知道最終結(jié)果3的位置上一定是1。
      ...
      所以c就是 10101000

       

      思路就是這樣。具體如何操作?

      a/b等于幾?
      b離a最近的又不超過a的,左移了幾位?5位。

      然后a 減掉 這個(gè)數(shù),再去看b左移幾位然后不超過a剛好夠的?左移2位。

      a再減掉這個(gè)數(shù),等于0,結(jié)束。
      a = b*2? + b*22,c就是:100100
       

      代碼實(shí)現(xiàn):

      package com.cy.class05;
      
      /**
       * 位運(yùn)算實(shí)現(xiàn)+-*\\/
       * 測(cè)試連接:https://leetcode.com/problems/divide-two-integers
       */
      public class Code03_BitAddMinusMultiDiv {
      
          public static int add(int a, int b) {
              int sum = a;
              while(b != 0) {
                  sum = a ^ b;            //無進(jìn)位相加信息   ->  sum
                  b = (a & b) << 1;       //進(jìn)位信息  -> b   ->  b'
                  a = sum;                //無進(jìn)位相加信息a  ->  a'
              }
              return sum;
          }
      
          /**
           * 返回n的相反數(shù)
           * 相反數(shù) = 取反 + 1
           * -n = ~n + 1
           */
          public static int negNum(int n) {
              return add(~n, 1);
          }
      
          public static int minus(int a, int b){
              return add(a, negNum(b));
          }
      
          /**
           * 乘法
           *
           * 右移:
           * b >> 1,表示右移1,最高位拿符號(hào)位來補(bǔ)。
           * b >>>1, 表示右移1,最高位一律拿0來補(bǔ)。
           *
           * 支持負(fù)數(shù),道理不好解釋,負(fù)數(shù)的情況下到底發(fā)生了什么,跟補(bǔ)碼有關(guān),你只要知道同樣這套方法既支持正數(shù)也支持負(fù)數(shù)。
           */
          public static int multi(int a, int b) {
              int res = 0;
              while(b != 0) {
                  if ((b & 1) != 0) {
                      res = add(res, a);
                  }
                  a <<= 1;
                  b >>>= 1;
              }
              return res;
          }
      
          public static boolean isNeg(int n) {
              return n < 0;
          }
      
          /**
           * 除法
           *
           * 這個(gè)方法在正式開始之前,a和b一定要都轉(zhuǎn)成正數(shù)
           *
           * x是非負(fù)的,第32位是符號(hào)位,肯定是0,所以沒必要右移31位。所以for循環(huán)i從30開始。
           *
           * 這里^的運(yùn)算是:非短路邏輯異或,兩邊的表達(dá)式都會(huì)執(zhí)行
           * boolean a = true, b = false;
           * boolean c = a ^ b; // true(不同時(shí)為 true/false)
           * 如果需要邏輯異或(對(duì)布爾沒必要值),直接用 != 更直觀: boolean xor = (a != b); // 等效于 a ^ b
           *
           * a ^ b: a和b不同返回true,否則返回false
           *
           * 這個(gè)除法必須要求x和y轉(zhuǎn)成正數(shù)的形式。
           * 這個(gè)方法一定是要能把a(bǔ)和b轉(zhuǎn)成正數(shù)才能繼續(xù)算,但系統(tǒng)最小值沒辦法轉(zhuǎn)絕對(duì)值,所以有局限。
           */
          public static int div(int a, int b) {
              int x = isNeg(a) ? negNum(a) : a;
              int y = isNeg(b) ? negNum(b) : b;
              int res = 0;
              // x / y
              for (int i=30; i>=0; i = minus(i, 1)) {
                  if ((x >> i) >= y) {
                      res |= (1 << i);
                      x = minus(x, y << i);
                  }
              }
              //如果a和b符號(hào)不一樣,取個(gè)負(fù)號(hào)返回;如果a和b負(fù)號(hào)一樣,直接返回答案
              return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
          }
      
          public static void main(String[] args) {
              int a = 7;
              int b = -3;
              System.out.println(multi(a, b));
          }
      
      }

       

      div方法解釋:
      1.代碼中是x/y,為什么看到x右移?y去夠x,和x去夠y,其實(shí)是一碼事。
       
      為什么是一碼事,看圖解:
      y要左移幾位才能夠上x?3位。

      同樣道理,x往右移幾位能讓y勾上自己?右移3位,所以x往右移看什么時(shí)候能夠上y,和y往左移看什么時(shí)候能夠上x,是一碼事。
      為什么要讓x往右移,因?yàn)閥這個(gè)玩意,左移的話有可能移動(dòng)到符號(hào)位上,就干了。
       
      如下圖,y左移的話,左移3位的話和x相等,要再左移1位才知道比x大了,才知道是左移3位。移4位的時(shí)候才知道上一位才是我應(yīng)該來的位置,但要過一位才能判斷出來,就有風(fēng)險(xiǎn)了。
      而x往右移沒這個(gè)風(fēng)險(xiǎn)。

      如下圖,x是一個(gè)很大的數(shù),y往左移去夠x,左移n位正好等于x,但是還需要左移一位大于x了后才知道上一位是該來的位置,繼續(xù)左移一位后到符號(hào)位了,y就變成負(fù)數(shù)了,還是不大于x啊。它還會(huì)左移,就會(huì)發(fā)生不可預(yù)知的錯(cuò)誤。

      x這個(gè)數(shù)如果不大沒什么問題。就怕它很大。

      所以為了安全起見,讓x去夠y。右移不會(huì)牽扯到改符號(hào)位的問題。右移不會(huì)有溢出問題。

       

      2.除不盡會(huì)怎樣?比如9 / 4:

      a - (b << 1)之后:
      a>>0后,并不比b大,for循環(huán)結(jié)束。res 等于2進(jìn)制的 10,返回2。所以div方法除不盡也沒事。
       
       
       
       

       

       

      --

      posted on 2025-05-04 20:01  有點(diǎn)懶惰的大青年  閱讀(113)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 久久精品一区二区东京热| 成人欧美日韩一区二区三区| 激情久久av一区av二区av三区 | 国产精品免费无遮挡无码永久视频 | 国产精品午夜福利视频234区| 亚洲av色夜色精品一区| 九龙县| 91中文字幕在线一区| 99久久精品国产一区二区暴力 | 免费观看全黄做爰大片| 好男人社区神马在线观看www| 国产精品老熟女露脸视频| 在线成人精品国产区免费| 久热久精久品这里在线观看| 国产成人一区二区不卡| 国产永久免费高清在线| 婷婷六月天在线| 国产人成777在线视频直播| 国产精品老熟女露脸视频| 国产精品成人观看视频国产奇米 | 亚洲人成电影网站 久久影视| 久99久热精品免费视频| 国产午夜福利精品久久不卡| 欧美成人精品在线| 国产亚洲精品久久久网站好莱| 欧洲熟妇色自偷自拍另类| 国产睡熟迷奷系列网站| 色婷婷久久综合中文久久一本| 国产麻豆成人传媒免费观看| 久久精品国产亚洲av麻豆小说| 亚洲熟妇色自偷自拍另类| 免费无码一区无码东京热| 国产高清自产拍av在线| 精品少妇爆乳无码aⅴ区| 红杏av在线dvd综合| 国产亚洲精品综合一区二区| 农村欧美丰满熟妇xxxx| 国产成人精品一区二区三区免费| 欧美日韩v| 午夜一区二区三区视频| 中文文精品字幕一区二区|