首页 > 其他分享 >原/反/补码与位运算的基础概念

原/反/补码与位运算的基础概念

时间:2024-05-22 16:44:38浏览次数:33  
标签:0000 运算 符号 补码 负数 概念 原码

零、参考资料

Under-One、一些技术概念

机器数与真值

  • 真值:在日常的书写习惯中,往往用正、负号加绝对值表示数值,用这种形式表示的数值为真值。例如100D,-50D,-76O等
  • 机器数:在计算机内部中使用的数,并且最高位表示符号的二进制数,又分为有符号数和无符号数。例如正数 7 用 8 位二进制数来表示:0000 0111
  • 机器数与真值之间的转换会使用一些原/反/补码的概念

计算

  • 计算机中统一使用的是加法计算 - 计算机不会减法

一、问题的产生 - 机器数的运算效率问题

问题:机器数是带符号的,而两个数相加,符号位是否参加运算,以及是如何运算的?
  • 两个正数相加(均以原码表示):
    0000, 1110 + 0000, 0001 = 0000, 1111 // 14 + 1 = 15 正确
    ^            ^            ^
    符号位        符号位        符号位
  • 两个负数相加(均以原码表示):
    1000, 1110 + 1000, 0001 = 0000, 1111 // (-14) + (-1) = 15 错误
    ^            ^            ^
    符号位        符号位        符号位(最高位的 1 溢出)
可以看到,在对机器数进行 "按位加法" 运算时,只有两个正数的加法运算的结果是正确的,而包含负数的加法运算的结果却是错误的。那么如何解决这个问题呢,数学上,我们可以:
  • 两个负数相加:
  1. 用较大的绝对值 + 较小的绝对值(加法运算)
  2. 最终结果的符号为负
  • 正负数相加:
  1. 判断两个数的绝对值大小(数值部分)
  2. 用较大的绝对值 - 较小的绝对值(减法运算)
  3. 最终结果的符号取绝对值较大数的符号
但是,在电路设计时需要这么复杂吗。有没有不需要设置减法器,而且步骤简单的方案?

二、原码、反码、补码

为了解决有符号机器数运算效率问题,计算机科学家们提出多种机器数的表示法:  
机器数 正数 负数
原码 符号位表示符号
数值位表示真值的绝对值
符号位表示数字的符号
数值位表示真值的绝对值
反码 无(或者认为是原码本身) 符号位为 1
数值位是对原码数值位的 “按位取反”
补码 无(或者认为是原码本身)  在负数反码的基础上 + 1
 
  • 原码:最简单的机器数,例如前文提到从 +1110 和 -1110 转换得到的 0000, 1110 和 1000, 1110 就是原码表示法,所以原码在进行数字运算时会存在前文提到的效率问题
  • 反码:一般认为是原码和补码转换的中间过渡
  • 补码:补码才是解决机器数的运算效率的关键,在计算机中所有 "整型类型" 的负数都会使用补码表示法

求负数补码的步骤:
  1. 得到这个负数的原码,如 -14 的原码是:1000 1110
  2. 保留符号位不变,将数值位取反,得到反码:1111 0001
  3. 将反码 + 1,得到补码:1111 0010
所以,拿到一个二进制数,其实首先应该问的是这个二进制是用何种形式表示的,是原码码值还是补码码值,然后在进行翻译。但是在实际中,负数一般都是用的补码码值,而正数的原码和补码又是一致的,所以我们在看到一个二进制数的时候,默认其是补码的表现形式。 所以在上面的两个负数的计算中,我们用补码进行计算的过程是:
1111, 0010 + 1111, 1111 = 1111, 0001 // (-14) + (-1) = (-15) 正确
^            ^            ^
符号位        符号位        符号位(最高位的 1 溢出)
由此,使用补码表示法后,有符号机器数加法运算就只是纯粹的加法运算,不会因为符号的正负性而采用不同的计算方法,也不需要减法运算,简化了电路设计 同时,除了消除减法运算外,补码表示法还实现了 "0" 的机器数的唯一性: 在原码表示法中,"+0" 和 "-0" 都是合法的,而在补码表示法中 "0" 只有唯一的机器数表示,即 "0000, 0000" 。换言之补码能够比原码多表示一个最小的负数 1000, 0000

三、补码背后的规律

具体与数学中的补数相关,这里简单举个例子来描述下规律:

时钟的例子

比如说,现在时钟的时针刻度指向 6 点,我们想让它指向 3 点,应该怎么做?
  • 方法 1:逆时针地拨动 3 个点数,让时针指向 3 点,这相当于做减法运算 -3
  • 方法 2:顺时针地拨动 9 个点数,让时针指向 3 点,这相当于做加法运算 +9
可以看到,对于时钟来说 -3 和 +9 竟然是等价的。 这是因为时钟只能 12 个小时,当时间点数超过 12 时就会自动丢失,所以 15 点和 3 点在时钟看来是都是 3 点。如果我们要在时钟上进行 6 - 3 减法运算,我们可以将 -3 等价替换为它的正补数 +9 后参与计算,从而将减法运算替换为 6 + 9 加法运算,结果都是 3

十进制的一个例子

如果计算 354365 - 95937,用补数的规律该怎么做?
354365 - 95937 // = 258428

= 354365 - (1000000 - 904063)

= 354365 - 1000000 + 904063 // 减整加补

= 258428

 

这里存在的问题是:为何是 1000000 ?这个 1000000 就相当于是时钟中的 12,是当前运算中的最大位数上限(周期之类的概念),这个数据似乎还和进制相关(这个有空再研究),所以实际上,运算的过程是:
354365 + 904063 = 1258428 = 258428
                  ^
                  最高位 1 超出位数限制,直接丢弃

 

总结

补码的关键在于:找到一个与负数等价的正补数,使用该正补数代替负数,从而将减法运算替换为两个正数加法运算。 补码的出现与运算器的电路设计有关,从设计者的角度看,希望尽可能简化电路设计和计算复杂度。而使用正补数代替负数就可以消除减法器,实现简化电路的目的

四、位运算

位运算是基于二进制值的运算(补码表现形式)
Operator Usage Description
按位与 a & b 在 a,b 的位表示中,每一个对应的位都为 1 则返回 1,否则返回 0
按位或 a | b 在 a,b 的位表示中,每一个对应的位,只要有一个为 1 则返回 1,否则返回 0
按位异或 a ^ b 在 a,b 的位表示中,每一个对应的位,两个不相同则返回 1,相同则返回 0
按位非 ~ a 反转被操作数的位
左移 a << b 将 a 的二进制串向左移动 b 位,右边移入 0
算术右移(有符号右移,其实就是保持符号位不变,数值位右移) a >> b 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位
无符号右移(左边空出位用 0 填充) a >>> b 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位,并把左边空出的位都填充为 0

五、位运算在 Javascript 中的应用

见下一篇

标签:0000,运算,符号,补码,负数,概念,原码
From: https://www.cnblogs.com/cc-freiheit/p/18206503

相关文章

  • PHP函数 算术运算符
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';//算术运算符/***+$a:标识;根据情况将$a转化为int或float。*-$a:取反;$a的负值。*$a+$b:加法;$a......
  • PHP函数 赋值运算符
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';//赋值运算符/***例子等同于操作*$a+=$b等同于$a=$a+$b加法*$a-=$b等同于$a=$a-$......
  • PHP函数 比较运算符
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';//比较运算符/***$a==$b等于true,如果类型转换后$a等于$b。*$a===$b全等true,如果$a等于$b,......
  • PHP函数 递增递减运算符
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';//递增/递减运算符/***递增/递减运算符例子名称效果*++$a前加$a的值加一,然后返回$a。*$a++......
  • PHP函数 逻辑运算符
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';//逻辑运算符/***$aand$b:And(逻辑与)true;如果$a和$b都为true。*$aor$b:O......
  • 冯诺依曼体系结构和总线概念
    Part1:计算机发展历程--冯诺依曼体系结构Pre:程序和存储是两种实现方式:程序属于ControlUnit,将程序用硬件实现,若更改程序,硬件需要重新设计Now:程序和存储都在内存中以二进制的方式保存。控制器在内存中取指,根据指令发送控制命令。             ......
  • C语言基本概念
    C语言基本概念概念​ 1、什么是语言:语言是人类进行沟通和交流的工具,广义上说,语言是一台共有规则的指令,指令可以通过文字,嗅觉、触觉等方式传递。​ 2、目的:实现人与人之间的交流,而当计算机出现了人与计算机交流,也需要一套共用的指令,所以就设计了一套编码与解码的指令,来给计算......
  • [转帖]Linux内存管理基本概念
    最近在学习Linux系统的内存管理,小白一枚,零散从网上收集的一些笔记如下:/proc目录提供了很多工具给我们查看当前内存情况1./proc/meminfo是什么$cat/proc/meminfoMemTotal:2052440kB//总内存MemFree:50004kB//空闲内存Buffers:19976kB/......
  • Doris:概念与基础操作
    Doris一款现代化的MPP分析性数据库产品支持亚秒级响应支持10PB以上数据集兼容MySQL协议基础概念doris有3种基础表:明细表(Duplicate):一张普普通通的表,doris默认表模式,支持数据预排序主键表(Unique):一种特殊的聚合表,如果主键重复,会自动更新其他值聚合表(Aggregate):聚合模......
  • 云渲染的概念与选择指南
    许多人在初次接触云端渲染时,可能会遇到各种疑问,比如云渲染的定义,以及如何选择合适的云渲染平台。为了帮助大家更好地理解这些内容,本文整理了有关云渲染的相关信息,希望能解答大家的疑惑。一、云渲染的概念云渲染是指将渲染任务提交到云端计算机,由云计算机代为完成渲染任务。通俗......