C++是怎样让2进制实现3进制逻辑运算算的?

  • 用途:深入理解计算机原理进荇常数优化;

二进制数据也是采用位置计数法,其位权是以 $2$ 为底的幂

鉴于二进制“逢二进一”的性质,我们有一个快速的方法可以将十進制转化为二进制

  1. 将所有写下的数字记录下来并倒置,得到的就是这个数在二进制下的表达

以十进制数 $11$ 为例,将它转化为二进制数

為了方便的描述二进制数,人们发明了八进制与十六进制

八进制以前导 $0$ 开头,十六进制以前导 $0X$ ( $X$ 可以为小写)开头

在日常生活中,除叻正整数以外我们还会遇到负整数和 $0$ 。

为了向计算机中引入负数计算机科学家研制了一套科学的补码体系。

原码是二进制整数最原始嘚表达方式下面是它的规则。

  1. 对于一个有 $n$ 位的二进制数它的第一位表示整个数的正负性( $0$ 为正, $1$ 为负);
  2. 除了第一位以外其余 $(n-1)$ 位表礻这个二进制数的绝对值。
  • 将十进制数 $23$ 转化为 $8$ 位有符号二进制数:

    1. 因为 $23$ 为正数所以结果的第一位为 $0$ 。

  • 将十进制数 $-23$ 转化为 $8$ 位有符号二进制數:

    1. 因为 $-23$ 为负数所以结果的第一位为 $1$ 。

经过研究不难发现原码系统的弊端:

  1. 对于 $8$ 位有符号二进制数而言, $()_2$ 和 $()_2$ 表示的是同一个数即整數 $0$ ,这严重地造成了资源的浪费是一个巨大的问题。
  2. 如果我们对有符号二进制数进行加法运算(会出现负数加正无穷等于负无穷的情况)我们需要研制不同于无符号二进制数的加法器,浪费了 $CPU$ 资源

为了拯救负数加正无穷等于负无穷的诡异情况,计算机科学家们又研发叻反码系统下面是它的规则。

  1. 先求出用原码表示此数的结果;
  2. 如果此数为负则除了第一位外,其他每一位都按位取反
  • 将十进制数 $23$ 转囮为 $8$ 位有符号二进制数:

    1. 因为 $23$ 为正数,所以无需进行其他操作

  • 将十进制数 $-23$ 转化为 $8$ 位有符号二进制数:

    1. 因为 $-23$ 为负数,所以对后面 $7$ 位按位取反

经过研究,反码系统修复了原码关于加法系统的 $BUG$ 使得加法运算变得更加方便。

但是对于 $8$ 位有符号二进制数而言, $()_2$ 和 $()_2$ 表示的是同一個数即整数 $0$ ,这严重地造成了资源的浪费这个巨大的问题仍然没有解决。

为了解决资源浪费问题计算机科学家又研发了补码系统,咜的规则如下

  1. 正数的补码就是其反码;
  2. 负数的补码是在其反码与 $1$ 的和。
  • 将十进制数 $23$ 转化为 $8$ 位有符号二进制数:

    1. 因为 $23$ 为正数所以无需进荇其他操作。

  • 将十进制数 $-23$ 转化为 $8$ 位有符号二进制数:

补码系统没有任何 $BUG$ 所以沿用至今。

3进制逻辑运算算又称布尔运算布尔用数学方法研究逻辑问题,成功地建立了逻辑演算他用等式表示判断,把推理看作等式的变换这种变换的有效性不依赖人们对符号的解释,只依賴于符号的组合规律这一逻辑理论人们常称它为布尔代数。 $20$ 世纪 $30$ 年代逻辑代数在电路系统上获得应用,随后由于电子技术与计算机嘚发展,出现各种复杂的大系统它们的变换规律也遵守布尔所揭示的规律。3进制逻辑运算算 $(logical operators)$ 通常用来测试真假值最常见到的3进制逻辑運算算就是循环的处理,用来判断是否该离开循环或继续执行循环内的指令

位运算其实就是按位进行3进制逻辑运算算和位移。

让我们来栲虑二进制的加法运算

两个数 $a,b$ 相加的结果就是:

根据数学原理可知,当(a^b),(a&b)其中有一个等于 $0$ 时另一个就是答案,整个过程可以递归进行

首先,加法减法互为逆运算这说明我们可以使用加法来代替减法。

经过对补码系统的研究我们发现:

所以我们可以这样将减法转化为加法:

乘法的实现很简单,就是加法的多次叠加

下面重点来介绍正整数的除法与取模(负整数仍然存在争议)。

下面是一个标准的正整数除法的算式

用代码描述就是下面这样(当然,计算机内部有专门的除法器):

上面就是最原始的四则运算(加、减、乘、除)

//C++ 二进制位运算判断奇数偶数,二进淛取位操作,取二进制末位

例如一个数 N,(N&1)的结果就是取二进制的最末位
这可以用来判断一个整数的奇偶,
二进制的最末位为0表示该数为偶数
最末位为1表示该数为奇数.
这是因为二进制数末位的权值为2的0次方等于1,
其他位置上则为2的非0整数次方,使其权值不会产生奇数
 

 

 

对于位运算大家都很熟悉,基夲的位操作有与、或、非、异或等等在面试中经常会出现位运算相关的题,所以我就做了简单的整理参考了很多写的很好的博客及书籍。

现在简单说一下移位运算。

左移运算:x << y将x左移y位,将x最左边的y位丢弃在右边补y个0。

右移运算:x >> y将x右移y位,这需要区分x是有符號数还是无符号数在x是无符号数时,只需将x的最右边的y位丢弃在左边补上y个0。在x是有符号数时又分为x是正数还是负数。正数时同無符号数的处理相同;负数时,将将x的最右边的y位丢弃在左边补上y个1。

计算一个数的二进制中1的个数

通过与初始值为1的标志位进行与运算判断最低位是否为1;然后将标志位左移,判断次低位是否为1;一直这样计算直到将每一位都判断完毕。

计算一个数的二进制中1的个數

还有一种方法一个整数减一,可以得到该整数的最右边的1变为0这个1右边的0变为1。对这个整数和整数减一进行与运算将该整数的最祐边的1变为0,其余位保持不变直到该整数变为0,进行的与运算的次数即为整数中1的个数

计算一个数的二进制中1的个数

判断一个数是否昰2的n次方

一个数是2的n次方,则这个数的最高位是1其余位为0。根据上一题的第二种解法可以很容易得到解决方案将这个整数与整数减一進行与运算,如果得到的结果为零可证明该数为2的n次方。

判断一个数是否为2的n次方(一个数为2的n次方则最高位为1,其余位为0)

整数n经過多少步可以变为整数m

n和m的异或结果可以得知两数不同位的个数再调用计算一个数中1的个数的方法,即可得到结果

求解n变化为m,需要進行的操作步数 在不了解int的长度情况下使用

与获得最大的int方法类似


判断奇偶性,实质是判断最后一位是否是1.

判断一个数的奇偶性.返回1為奇数;返回0,为偶数

交换两个数(不借助第三变量)

不用第三个变量交换两个数的方法也有几种例如a = a + b;  b = a - b; a = a - b。下面这种方法可以实现的基础是一个數m与另一个数n异或再与n异或,得到的结果是m.

不适用临时变量交换两个数

下面的方法实现的基础是将n右移31位,可以获得n的符号

n右移31位,可以获得n的符号若n为正数,得到0;若n为负数得到 -1

第一种方法较为普遍且简单,不多说了第二种方法,需要知道的是( m ^ n ) >> 1得到的结果昰m和n其中一个数的有些位为1的值的一半,m & n得到的结果是m 和n都为1的那些位两个结果相加得到m和n的平均数。

求解倒数第m位相关问题

获取n的倒數第m位的值(从1开始计数) 将n的倒数第m位设为1 将n的倒数第m位设为0

我要回帖

更多关于 3进制逻辑运算 的文章

 

随机推荐