【数字IC/FPGA】什么是无符号数?什么是有符号数?

news2024/12/26 21:57:51

进制

虽然在日常生活中,我们已经习惯了使用10进制数字,但在由数字电路构成的数字世界中,2进制才是效率更高的选择。

10进制与2进制

10进制(decimal)计数法(一般也叫阿拉伯计数法)是在日常生活中使用得最多的一种计数法,它是一种位值记数法(positional notation)。位值计数法的意思是不同位置的数字有着不同的权重(weight),即不同的值。比如数字 ”333“ ,第一个数字3表示的是三百(3×100),第二个数字3表示的是三十(3×10),第三个数字3则是表示三(3×1)。

罗马计数法也是10进制的,但不同的是,它不是一种位值记数法,而是加减制的。它的一般规则是:

罗马数字只有七个符号:Ⅰ,Ⅴ,Ⅹ,L,C,D,M 。它们依次代表1,5,10,50,100,500,1000。相同数字并列时就相加,不同数字并列时,小数放在大数的右边就作为加数;放在大数的左边(限于基本符号),就作为减数。

罗马记数法记较大的数十分冗长,例如 “3888” 就要记作 MMMDCCCLXXXVIII,书面计算更麻烦,故一般不通用。

10进制有 0~9 共十个数字,所以它 “逢十进一”,当然也可以说它的基数是十。2进制(binary)则只有0和1这两个数字,所以它 “逢二进一”,或者说它的基数是二。二进制计数法也是一种位值记数法,它的不同位置的 “ 0 或 1” 有不同的含义。例如数字 “1101” 的第一个数字1表示的是8(1×23),第二个数字1表示的是4(1×22),第二个数字0表示的是0(0×21),第四个数字1则是表示1(1×20)。

image-20240402152111026

据说人类之所以使用10进制,很大可能是因为人类有10根手指。这一说法我不知道是否正确,但我知道数字电路之所以使用2进制是因为电路有两个很明显的状态:”关“ 和 ”开“。

8进制和16进制

除了2进制外,8进制(Octal)和16进制(hexadecimal)在数字电路中也很普遍。它们可以很方便地分别将2进制数字分为3个一组和4个一组,从而方便了多位2进制数的书写和阅读。

8进制以8为基数,共使用 0~7 这8个数字。因为2的3次方是8,所以3个2进制数字可以很方便地转化成一个8进制数字,例如2进制数字 “110_010” 可以转化成8进制数字 “62”。

image-20240402154945560

类似的,16进制以16为基数,共使用09,加AF这16个数字。因为2的4次方是16,所以4个2进制数字可以很方便地转化成一个16进制数字,例如2进制数字”1101_0001“ 可以转化成16进制数字 “D1” 。

image-20240402154951591

不同进制之间的转换如下(部分数字):

image-20240402153100654

原码、反码和补码

原码、反码和补码是2进制数的3种不同表示形式,关于这个概念,我在这篇文章中有一个详尽且通俗的说明,如何简单理解原码、反码和补码?

我们先来了解一个概念:模数系统。所谓模,是指一个计数器的容量,或者称模数。例如,常见的圆盘式钟表就是一个以12为模的模数系统。因为它的模是12,所以它只能表示1~12这12个数,超出12的数就无法表示了。

bTy6Ky8ac

假设现在你在一个见不到外面光线的房间,发现钟表正指向11点整的位置。仅根据这个信息,你是无法直接判断当下是上午11点还是下午11点(即23点)的。下午11点也是23点,所以在模12系统中,23就等于11,这可以表示为:23 = 11(mod12),也称23和11对模12是同余的。

原码

原码就是某个数的2进制形式,比如10进制数字 “3”,如果用4位二进制数表示,则是 “0011”,4个位可以表示从 “0000~1111” 这16个数字(即10进制的0~15)。

这种方法有个问题就是只能表示正数,不能表示负数。在10进制系统中,我们表示负数的方法是在前面添加负号“-”,比如“-5”就是负5,而“5”和“+5”则是正5,因为正数的使用更常见,所以“+“ 号大多数时候都会被约定俗成地给省略掉。

2进制的使用场景主要是数字电路,电路只能识别 “0” 和 “1”(高电平和低电平),识别不了 “正负符号 +/- ” ,所以使用 符号“+/-” 来区分正负的方法行不通。既然一个2进制单位可以表示0/1,即可以表示两种状态,那么我们就可以单独把其中一个数拿出来表示这个数字是正数还是负数。通常的做法是把最高位拿出来表示正负,并约定:若该数为1则为负数,若为0则为正数。

这样的话,就有:

+5 = 0_101,-5 = 1_101

”+5“ 和 “-5” 除了最高位的符号位不同外,剩余3位都是相同的。

这种方法也有问题,那就是没法直接做计算。按理说(+5)+(-5)= 0,但是 0101+1101 = 1_0010,如果不截断第5位,那它的结果是 “-2”,如果截断,那它的结果是 “2”。不管怎么处理,它的结果都和正确结果 “0” 对不上。

补码

我们希望设计的是这样一种系统:它不光可以表示正负,同时还可以直接做运算。例如(+5)+(-5)= 0 我们希望在这一表示系统中也可以直接实现。

(+5)+(-5)因为是加法,所以它的结果怎么都不可能是 “0000”,但是,它有没有可能是 “1_0000” ? 完全有可能!因为 “1_0000” 就是10进制的 “16”,从上面说的模数系统的概念中可知,16和0对模16同余,也就是说在一个模16的系统中,16就是0,0就是169!

刚好4位2进制数就是一个模16的系统!再来看这个式子: 0101 + 1011 = 10000,而我们希望得到的是 “0000” ,这意味着最高位的1可以被舍弃掉。这个过程是不是可以看做是结果减了 “16”(从 “10000” 到 “0000” 相当于减16)? 如果将原本表示10进制数 “-5” 的 “1011” 若视为10进制正整数的话,那就是则是 “11” ,也就是说 0101 + 1011 = 5 + 11 = 16 ,然后舍去最高位相当于-16,所以最后结果为0!补码的出现把减法变成了加法!

image-20240402164513452

“-5” 的表示就很清晰了,1_0000 - 0101 = 1011,这种表示方法就叫做补码。补码是通过将负数转换成同余数并利用溢出,从而实现减法和负数表示的一种方法。

例如 “-10” 的8位补码是这么求的:

8位数的模为256,“-10” 与 “246” 对模256同余,所以 “-10” 的补码就是 “246” 的原码,即 “1111_0110” ;也可以用 “256 - 10” 的方法来求,即 1_0000_0000 - 0000_1010 = 1111_0110,二者结果是一样的。

反码

你可能听过:正数的原码等于它自身,而负数的原码则等于符号位不变的其他位取反加1,而符号位不变的其他位取反又被称为反码,所以负数的补码等于其反码加1。

在我看来,反码仅仅只是拿来求补码的中间产物,并没有太多的其他作用。

任何一对绝对值相同的正数和负数,其正数原码与负数的反码相加,其值都是全1。例如 “+42” 原码是 “0010_1010”,“-42” 的反码是 “1101_0101” ,加起来就是“1111_1111” 。显然,之所以会出现这种情况,是因为这两个数的每位都是相反的。我想这可能也是反码(ones’ complement)这个中文译名的由来。

462fa69344523191c4bd9efa4352dc5d

反码的英文名叫Ones’ complement,粗暴点翻译就是 “1们的补集” 或者 “多个1的补集”。反码本质上是在求正数的算术负数,也就是说,将数字的所有位取反产生的结果与从 0 中减去该值的结果相同。

式①:负数的补码 =容量(模) - 负数的绝对值

8位字长下,任何一个负数与其反码相加结果均为全1,即 正数原码 + 负数反码 = 1111_1111。8位字长下容量是1_0000_0000,即2^8 = 256,而1_0000_0000 = 0_1111_1111 + 0_0000_0001。也即

式②:容量(模) = 1111_1111 + 1 = 正数原码 + 负数反码 + 1

结合①②式,有

负数的补码 = 正数原码 + 负数反码 + 1 - 负数的绝对值 = 正数原码 + 负数反码 + 1 - 正数原码 = 负数反码 + 1

这也就是常说的:负数的补码等于取反加1 。这样就把对负数求补码的运算在电路上给转换成了 按位取反加法(+1) 运算了,这是数字电路很容易实现的形式。

所以说,根据取反加1来求负数的补码只是一种简便方法,而并不是一般定义。一般定义仍是:

负数补码 = 模(容量) - 负数对应的绝对值。

无符号数和有符号数

了解了原码和补码后,就很容易理解无符号数(unsigned number)和有符号数(signed number)了。

无符号数是一串最高位不表示符号,只表示数值的二进制数序列。相反,有符号数则是最高位用来表示符号。例如同样的4位补码表示 “1001” ,如果看做是无符号数的话,那它等于10进制的 “9” ;如果看做是有符号数的话则是 “-7”。

image-20240404171854732

无符号数和有符号数在相同位数下可以表示的数字个数是一样多的,但是表示范围却不一样。例如,8位2进制无符号数的表示范围是 “0~255”,而8位2进制有符号数的表示范围是 “-128~127”。

求有符号数的10进制值

无符号数的转换比较简单,只要把每个位上的数按权重加起来就可以,例如4位的 “1101”,结果就是 8+4+0+1 = 13。有符号数的转换按照传统的取反加1方法则麻烦一点,比如4位的 “1101”,先取反后是 “1010” ,再加1是 “1011” ,最高位表示是负数,剩余的 “011” 为是数值即 “3”,最终结果为 “-3” 。

其实,有一种更简便的求有符号数的10进制值的办法,那就是把最高位同样纳入带权重的加法,但是权重为 “ -1 ” 。例如4位的 ”1101“ ,就是 -8+4+0+1 = -3,这样和上面一种方法求得的结果是相同的。

原理是什么呢?因为4位二进制数的模是8(除去符号位只有3个有效位),从上面的推断可知,负数的补码除去符号位外剩余的数值是其在该模下的同余数,例如 “1101” 除去符号位是 “101” 即 10进制数“5”,最高位的权重为 “-1 ”,实际就相当于减去模值8,即 “1101” 相当于 5 - 8 = -3。

有符号数的高位扩展

10进制数 “-3” 用4bits来表示是 “1101” ,用5bits表示呢?答案是 “11101”。6bits到8bits的表示则分别是 “111101”,“1111101”,“11111101”。

4bits1_101
5bits11_101
6bits111_101
7bits1111_101
8bits1111_101

可以看到,每次将位宽拓展一位,都是在补码的最高位补1。同时,对正数的扩展,毋庸置疑肯定是在高位补0。二者结合起来就是补码的高位扩展是补符号位

正数的高位扩展补0没什么好讨论的,和10进制的 “1” 和 “01" 是同样的数值一样,2进制的 “0111” 和 “001111” 显然也是同一个数值。但是负数的高位扩展为什么也只要补符号位就行?理解这一点有两个方法。

方法1:往高位扩展1后,原本的最高位变成了次高位,次高位的权重从-1变成了+1,而最高位的权重又相当于次高位的2倍,二者相加后,相当于这两位在加法中的和根本没变。例如 ”-3“ 的4位补码 ”1_101“ ,原码可以看做是 -8 + 5 = -3,变成5位补码后(11_101)则是(-16+8) + 5 = -8 + 5 = -3。

方法2:根据负数的补码是除符号外取反加1来求的方法可知,往高位补1后,次高位的1取反加1后只有一种情况不是0,而这个0是不会对结果有影响的。例如 ”1_101“ 扩展到 ”11_101“ ,取反是 ”10_010“ ,加1后是 ”10_011“ ,只要低3位不是 ”000“ ,那么取反加1后就不会溢出,也就不会对次高位产生影响,从而保证了次高位一直是 ”0“ 。溢出的情况则比较特殊,仍以4bits数为例,只有 “1000” 这么算会产生溢出,但是 “1000” 即10进制的 “-8” 在4bits情况下是不存在原码和反码的。但从方法1中可知,“1000” 和 “11000” 都是 "-8"的补码,所以高位补符号位的规律仍然适用。

无符号数的加法与溢出

2进制数的加法同10进制类似,都是逢基数进一。以两个4bits无符号数 6 + 4 = 10为例,它的计算过程是这样的:

image-20240402175830928

需要注意的是,两个4bits数相加是有可能产生5bits的和的,所以我们一般会把结果扩大到5bits,以防止溢出。例如14 + 8 = 22 的计算过程(有溢出)是这样的:

image-20240402175816328

有符号数的加法与溢出

因为减法可以转换成加法,所以两个有符号数的加法只有3种情况:

  • 正数 + 正数
  • 正数 + 负数
  • 负数 + 负数

接下来分别进行讨论。

1、正数 + 正数

情况类似上面讨论的无符号的加法,仍以 0110 + 0100 = 1010 为例,由于此时的结果为有符号数,故结果 “1010” 会被看做是 “-6” ,这显然不是 (6 + 4 = 10)的预期结果。

产生这一现象的原因是4bits的2进制有符号数最多只能表示 ”7“,而不能表示 ”10“,超出了范围产生了溢出。解决方法是将结果扩展一位,这样最后的结果就是01010,等于10进制数“10”,结果正确。

image-20240402211330076

2、负数 + 负数

和 “正数 + 正数” 的情况类似,结果可能会溢出,所以也建议把结果扩展一位。

有一种情况类似(-1)+(-3)=(-4),尽管结果 “11100” 产生了高位溢出,但是这个溢出是可以被省略掉的,因为 “11100” 和 “1100” 都是 “-4” 的补码,只是位数不同罢了。和正数往高位补0不会改变数值一样,负数补码往高位补1同样不会改变数值。

image-20240402211857008

还有一种情况则比如(-3)+(-6)=(-9),结果 “10111” 如果舍去最高位,则变成了 “0111”(10进制数 “7” ),这样明显和预期结果不符。但如果把结果扩展一位,则是 “10111” ,即10进制的 “-9” ,与预期结果相符。

image-20240402212135387

3、正数 + 负数

正数 + 负数 等同于减法,减法的结果肯定比被减数小,所以理论上不会有溢出。但是2进制负数是使用补码来表示的,从而将减法转换成了加法,而加法则可能产生溢出,但这个溢出并不会影响运算结果。相反,减法的实现反而还依赖这个溢出。

例如 5 +(-2)= 3,如果结果只取低4位,那就是对的;如果结果也扩展一位,那反而出错了。

image-20240402213334067

对上面三种情况的分析可知,其中有2种运算的结果可能会产生溢出(正数 + 正数、负数 + 负数),为了防止运算错误,需要将结果扩展一位。而正数 + 负数这种情况,若也将结果扩展1位则会运算错误。

问题是很多时候,我们做计算是无法保证输入的数据只是正数或负数,上面这3种情况可能在同一个模块中都会出现,为了保证设计的通用性,我们希望能有一种方法可以同时满足上面三种情况。

为此可以这样尝试:两个 N 位二进制补码相加,为了防止结果溢出产生错误,可以将两个加数进行符号位扩展,变为 N+1 位数,然后相加,结果也拓展到N+1位数。

正数 + 正数 的情况很显然,往正数的高位补符号位(0)后,相当于结果的最高位也多了一个0,所以不会对结果产生影响。

image-20240402214803493

负数 + 负数 的情况类似,相当于结果的最高位多了一个1,同样不会对结果产生影响。下面产生了6位结果,而我们定义的位宽为5位,所以最终结果仍是符合预期的。

image-20240402215054540

正数 + 负数 ,需要分别对其高位补0和补1,最终的运算结果因为存在负数补码的关系肯定也会溢出一位,但是最高位会舍去,所以结果也是就是正确的,比如:

image-20240402215417093


  • 📣您有任何问题,都可以在评论区和我交流📃!
  • 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1595501.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ | Leetcode C++题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummy new ListNode(0, head);ListNode* first head;ListNode* second dummy;for (int i 0; i < n; i) {first first->next;}while (fi…

UE4_导入内容_骨架网格体

FBX 导入支持 骨架网格体&#xff08;Skeletal Mesh&#xff09; 。这提供了一种简化的处理流程来将有动画的网格体从 3D应用程序中导入到虚幻引擎内&#xff0c;以便在游戏中使用。除了导入网格体外&#xff0c;如果需要&#xff0c;动画和变形目标都可以使用FBX格式 在同一文…

IDA导入jni.h头文件步骤

源地址&#xff1a;https://www.ctvol.com/asreverse/2273.html 导入步骤1&#xff1a; 点击IDA Pro 菜单项“File->Load file->Parse C header file ” 选择jni.h头文件。 导入步骤2&#xff1a; 1、点击IDA Pro 主界面上的“Structures”选项卡。 2、按下Insert键…

为什么会有c++内存模型

1. 引言 c的内存模型主要解决的问题是多线程的问题。怎么理解多线程呢&#xff1f;单核时候&#xff0c;只有1个CPU内核处理多线程&#xff0c;各线程之间随着时间的推进&#xff0c;会不断的切换&#xff0c;如下图形便于理解。 实际上线程间的切换是非常快的&#xff0c;所以…

OpenHarmony实战开发-异步并发概述 (Promise和async/await)。

Promise和async/await提供异步并发能力&#xff0c;是标准的JS异步语法。异步代码会被挂起并在之后继续执行&#xff0c;同一时间只有一段代码执行&#xff0c;适用于单次I/O任务的场景开发&#xff0c;例如一次网络请求、一次文件读写等操作。 异步语法是一种编程语言的特性&…

信息系统项目管理师——管理类计算

风险管理——风险曝光度 风险曝光度概率*影响&#xff0c;概率指风险发生的概率&#xff0c;影响指风险一旦发生&#xff0c;受到影响的项。 题号【GX20061101](61) 知识点[风险曝光度] 风险的成本估算完成后&#xff0c;可以针对风险表中每个风险计算其风险曝光度。某软件小…

h5 笔记4 表格与表单

<table></table>设置表格&#xff1b; <tr></tr>设置行数&#xff1b; <td></td>设置列数&#xff1b; <caption></caption>设置表格标题&#xff1b; <th></th>设置列标题。 直列&#xff1a;column&#xf…

LeetCode 678——有效的括号字符串

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 需要两个栈&#xff0c;一个用来保存左括号所在的位置索引&#xff0c;一个用来保存星号所在的位置索引。 从左往右遍历字符串&#xff0c;如果是左括号或者星号&#xff0c;则将位置索引分别入栈&#xff0c;如…

【网站项目】面向企事业单位的项目申报小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

精通技术写作:如何写出高质量技术文章?

CSDN 的朋友你们好&#xff0c;我是未来&#xff0c;今天给大家带来专栏【程序员博主教程&#xff08;完全指南&#xff09;】的第 7 篇文章“如何撰写高质量技术文章”。本文深入探讨了如何写好一篇技术文章。文章给出了好的技术文章的定义和分析&#xff0c;并提供了从选题、…

02 MySQL 之 DQL专题

3. 数据库中仅有月薪字段&#xff08;month_salary&#xff09;&#xff0c;要求查询所有员工的年薪&#xff0c;并以年薪(year_salary)输出&#xff1a; 分析&#xff1a; 查询操作中&#xff0c;字段可以参与数学运算as 起别名&#xff0c;但实际上可以省略 #以下两句效果…

202209青少年软件编程(scratch图形化) 等级考试试卷(四级)

第1题&#xff1a;【 单选题】 运行下列程序&#xff0c;说法正确的是&#xff1f;&#xff08;&#xff09; A:列表中的数字全部小于11 B:列表的长度为 10 C:变量i最终值为 20 D:列表中有大于 10 的数字 【正确答案】: D 【试题解析】 : 程序运行后&#xff0c;变量i最…

SSRF+Redis未授权getshell

SSRFRedis未授权getshell 1.前言 当一个网站具有ssrf漏洞&#xff0c;如果没有一些过滤措施&#xff0c;比如没过滤file协议&#xff0c;gophere协议&#xff0c;dict等协议&#xff0c;就会导致无法访问的内网服务器信息泄露&#xff0c;甚至可以让攻击者拿下内网服务器权限 …

Hadoop 3.1.3

第1章 Hadoop概述 1.1 Hadoop是什么 1.2 Hadoop发展历史&#xff08;了解&#xff09; 1.3 Hadoop三大发行版本&#xff08;了解&#xff09; Hadoop三大发行版本&#xff1a;Apache、Cloudera、Hortonworks。 Apache版本最原始&#xff08;最基础&#xff09;的版本&#x…

【学习笔记十一】EWM上架目标仓位确定过程及配置

一、EWM确定目标区域概述 1.EWM从仓库处理类型获取源仓库类型&#xff08;Source storage type&#xff09;和源仓位&#xff08;Source Bin&#xff09;2.EWM根据仓库类型&#xff08;storage type&#xff09;、仓库分区&#xff08;storage section&#xff09;和上架策略&a…

待研究技术

Fabric.js H5 Canvas的js库 Fabric.js是一个用于创建交互式的HTML5 Canvas应用程序的JavaScript库。它提供了一个简单而强大的API&#xff0c;用于在Web浏览器中绘制和操作图形对象。Fabric.js可以用于创建各种图形应用程序&#xff0c;例如绘图编辑器、图像编辑器、流程图、地…

做产品,我的转行+转岗经历

许多小伙伴在后台留言提到数据产品经理这个岗位&#xff0c;今天来给大家介绍一下数据产品的一些基本工作内容和流程&#xff0c;帮助大家了解。 之前写了一篇转行PM的历程文章&#xff0c;有很多像我当年一样在求职中的小伙伴私信我&#xff0c;这其中有应届生也有程序员&…

基于Springboot+Vue的Java项目-房产销售系统(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

雅虎、乐天、煤炉、国际站、newegg、wish等跨境卖家如何提升店铺销量?深度解析自养号测评的价值

一、如何提升销量&#xff1f; 优化产品描述和图片&#xff1a;确保您的产品描述准确、详细&#xff0c;图片清晰、美观。这将有助于提高产品的吸引力&#xff0c;增加潜在买家的购买意愿。 提供良好的客户服务&#xff1a;及时回复买家的咨询和问题&#xff0c;解决他们的疑…

Mixed-Query Transformer:统一的图像分割架构

Mixed-Query Transformer:统一的图像分割架构 摘要IntroductionRelated WorkMethodMQ-Former ArchitectureObject Query Strategies Mixed-Query Transformer: A Unified Image Segmentation Architectur 摘要 在现有的一体化图像分割模型中&#xff0c;要么在多个任务上采用统…