精华内容
下载资源
问答
  • 补码的计算规则是怎么?计算机是如何区分unsigned intint?众所周知,二进制是一种记数系统(类比十进制),而补码就是该系统之上编码协议。协议是为了无序信息流变得规整,让人能够控制它。从这方面猜测,...

    上下文约束

    默认围绕8位计算机展开讨论。

    问题

    在进入正文之前,先提三个问题:

    1. 计算机中的数为什么用补码(2's complement)来表示和存储?
    2. 补码的计算规则是怎么来的?
    3. 计算机是如何区分unsigned int和int?

    众所周知,二进制是一种记数系统(类比十进制),而补码就是该系统之上的编码协议。协议是为了无序信息流变得规整,让人能够控制它。从这方面猜测,补码产生的原因是为了最小化硬件设计的成本,这大概也是最初的软件定义硬件(SDH)。

    当我们想象比特流的存储过程时,不免好奇自己头脑中的数值概念(尤其是负数和小数)怎么被计算机编码成有意义的比特流?这些比特流如何被正确地计算成另一种比特流?在更高层次上,编程语言中的short, int, unsigned int, long, long long等数值类型是怎样被计算机正确地识别的?

    通常,协议是处理复杂度的好方法,但隐藏在协议背后的原因比它本身更有探索的价值。如果你也感同身受,那么阅读下文就是合适的。

    为什么用补码?

    概念解释

    1. 原码[1](True form)
      原码是指一个二进制数左边加上符号位后所得到的码,且当二进制数大于0时,符号位为0;二进制数小于0时,符号位为1;二进制数等于0时,符号位可以为0(+0)或1(-0)。
    2. 反码[2](One's complement)
      反码是带有符号位的二进制数表示;负数的反码是将其对应正数按位取反,正数和0的反码就是该数字本身。
    3. 补码[3](Two's complement)
      补码也是带有符号位的二进制表示;负数的补码是将其对应正数按位取反再加1,正数和0的补码就是该数字本身。

    三者的关系很密切,是1对1的单射关系。准确地说,补码下可表示的最大负数没有对应的原码和反码。具体原因,待会儿做详细讨论。

    从实际应用的角度提问,现代计算机中数据的存储形式是原码、反码还是补码?这个问题其实可以规约到另一个问题上——哪种存储形式最有利于计算机进行运算?从这个角度思考就不难得出答案,当然是补码,不然,要是原码和反码都够用,为啥设计出补码?

    那么,为什么原码和反码不够用?单独从数据表示来看是无法得出结论的,需要从计算的角度思考。我们都知道,二进制是以2为基数的记数系统,和十进制、六十进制的记数本质相同。在最开始,记数系统中是没有负数的,引入负数是为了统一概念相反的事物。比如:收入和支出,支出就可以视为负的收入。如果用恒等式表达收支平衡收入 = 支出,将支出移项到左边就得变号收入-支出 = 0,换句话说,收入+(-支出) = 0,此时表达了总收入为0这个事实。相同的概念对于运算的意义重大,以前需要设计减法的运算规则,现在用加法规则就可以替代。在人类看来,这意味着概念的统一,而对于计算机而言,这简化了ALU(算术逻辑单元)中集成电路的设计。

    既然如此,负数在二进制中的表示就尤为重要。按照原码的定义,-1的二进制表示是1000 0001,那么计算1-1,也就是计算0000 0001 + 1000 0001 = 1000 0010,这个数表示的是十进制中的-2。1-1=-2当然是错的,它为什么是错的呢?因为符号位也参与运算了,上面的算式其实表达的是1+129=130这个算式。

    看到这里,或许需要思考的是数的表示和它们之间的运算是不对称的疑问?究其缘由是,数在计算机中表示是人为定义的,我们规定了左边的1是符号位,但是ALU不知道,而且也不应该知道。为什么呢?因为人是善变的,后面还会出现无符号数,那时候左边的1可就不能视作符号位。

    在继续探索之前,我们先补充点数学知识。

    同余

    当两个整数除以同一个正整数,若得相同余数,则这两个整数同余[4]。记为:

    读作a与b关于模m同余。同余的数具备很多性质,其中有一条保持基本运算:

    我们用这个数学性质来推导一下日常生活中的12小时制计时法。

    0点和12点关于12点同余,5和5当然关于12点同余,那么有:

    所以5和17关于12同余。当我们说下午5点时,其实也就是在说17点。负数也满足这样的关系,即-5和7关于12同余。

    负数的反码

    按照定义我们求得-1的反码,1000 0001的反码为1111 1110即254,-1和254相对于255(1111 1111)同余。依据同余的基本性质,

    取c为1,那么

    即0和255相对于255同余。当然,正确性显而易见。但是,这里面也出现了一个问题,0和255(-0)都是0这个数在反码中的正确表达,这也是负数的反码表示数的范围是[-127, 127],总数是255个的由来,就像12小时制计时0和12都是零点的表达,那么对于判0运算而言,就得有两手准备。简单起见,有没有其他方式去掉这种特殊情况呢?于是,补码顺势上位。

    负数的补码

    由于0和255都是8位计算机中0的合法表达,容易想到的一种方法就是去掉一个,而且还得保留同余的性质。

    假如把相对于255的同余变成256的同余是否有帮助呢?此时,0和256就相对于256同余了,但是因为8位二进制只能表示[0, 255]范围的数,再多就溢出了,256是没法表示的。我们还是以-1举例子:

    取c为1,那么

    0和256同余,即0000 00001 0000 0000同余,溢出位1被舍去,就变成了0000 0000

    负数的补码数的表示范围为[-128, 127],这个-128是怎么来的呢?它的补码表示是1000 0000。要解答这个问题,得看看原码和反码中的0的表示。

    先看看原码,左边第一位是符号位,说明它把0~255个数分成了两半,分别是0~127, 128~255。其中,0000 00001000 0000都表示0,所以它只能表示255个数。即,-127~127.

    类似地,反码中的0000 00001111 1111也都表示0,其中1000 0000表示-127,所以它也只能表示255个数。即,-127~127.

    但是补码就不同,它里面的0就只有一个0000 0000,而-128和128相对于256同余,但是128(

    )在8位机器上没法表示,所以干脆把
    1000 0000直接拿来当-128,可想而知,这个数是没法通过原码取反加1计算出来的,因为它对应的原码并不存在(整数128是不存在的)。

    补码的计算规则是怎么来的?

    正数的补码就是其本身;
    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1

    先说说反码计算方式的由来。以-1为例,其原码表示如下:

    1000 0001

    那么为何对它符号位之外进行取反,就得到了它相对于255(1111 1111)的反码呢?

    我们用255减去-1的绝对值,试试看

    1111 1111
    - 0000 0001
    -----------
      1111 1110

    1111 1110就是254,它和1000 0001保留符号位后各位取反的结果一致。这是巧合吗?显然不是,因为1111 1111是8位中最大的数,所以就不存在借位操作,那么各位减下来,位是0的自然得到1,位是1的自然得到0.

    -1和254相对于255同余,所以-1是254的补(One's complement)。不信的话,可以去clojure repl中运行下面的表达式。

    (mod -1 255) #=> 254

    知道到了反码的求值方法的由来,我们不难推断出补码的计算方法。因为256是255+1,取反就是用255减去该数,那么用256减去该数,也就等价于255减去该数再加一。

    利用这个知识点,我们推导下早期的的计算机中使用的加三码(excess-3),这种编码方式是利用了4位来表示数字0-9。

    0 -> 0011
    1 -> 0100
    2 -> 0101
    ...
    8 -> 1011
    9 -> 1100

    这种表示有什么好处呢?加三码中针对0-9中任意一个数x,9减去x得到的数的表示和x的各位取反之后的数是相同的。因为这样的特征,设计减法电路就非常方便了。

    9-1=8
    1 -> 0100
    取反 -> 1011
    即:8 -> 1011

    当然这也不是巧合。理由很简单,4位最大表示数是15,所以9-x可以写成下面的等式

    1100-x+0011 = 1111-x

    所以等同于对x的取反。

    计算机是如何区分unsigned int和int的?

    我们已经知道了计算机存储数据全部用的补码的形式,所以从内存中拿出来的数就是补码,那么-1的补码是1111 1111,也就是数2^8-1=255.

    如果说unsigned int的存储形式和int的一致,那意味着int负数转换成unsigned int的值就是它补码的字面值。我们使用Solidity语言程序验证,在验证之前,先要安装ganache-cli和solidity-repl.

    $ ganache-cli
    ...
    $ solr
    Welcome to the Solidity REPL!
    > int8 c = -1
    > uint8 d = uint8(c)
    > d
    255

    -1的补码是1111 1111,也就是十进制的255,所以从结果中不难得出如下结论:在计算机中,数的存储和表示是分开的,存储的是补码,计算过程也使用补码,但是最后的表示由程序员来决定。所以毫不夸张地说,程序员是规则的缔造者,也是规则的解读者。


    顺带一提
    solidity中的int和uint是成对的,而且从8, 16, 24, ..., 256,一共有32个。正确性可以通过它的词法分析程序得出来。

    //solidity/liblangutil/Token.cpp
    
    if (0 < m && m <= 256 && m % 8 == 0 && positionX == _literal.end())
    {
        if (keyword == Token::UInt)
            return make_tuple(Token::UIntM, m, 0);
        else
            return make_tuple(Token::IntM, m, 0);
    }
    展开全文
  • 32位无符号整数 , 其表示范围是232次方,最大整数为 232次方-1 有符号数则要去除一个符号位,正数最大为231次方-1 , 负数最小为负 231次方    16位整数同理。 int 在32位系统中为 4字节,也就是...

    32位无符号整数 ,  其表示范围是2的32次方,最大整数为 2的32次方-1
    有符号数则要去除一个符号位,正数最大为2的31次方-1 , 负数最小为负  2的31次方 
     
    16位整数同理。

    int  在32位系统中为  4字节,也就是32位。在一些16位系统中,int 为2字节,在64位系统中int为8字节。

     

    直接用下面这些来表示好了(始终不会错的):
    unsigned int的范围:
    最大值(unsigned int)-1,最小值0
    int的范围:
    最大值(int)((unsigned int)-1 >> 1U),最小值(int)~((unsigned int)-1 >> 1U)

    展开全文
  • 一个byte由八个位组成,符号位 + 数值位,如x0000000,其中第1位是符号位,后面7位表示数值,第1位是符号位(0为正,1为负)。这样+1就是00000001,-1就是10000001。最大正数就是0 1111111,即20+ 21+……+26=...

    一个byte由八个位组成,符号位 + 数值位,如x0000000,其中第1位是符号位,后面的7位表示数值,第1位是符号位(0为正,1为负)。这样+1就是00000001,-1就是10000001。最大的正数就是0 1111111,即20+ 21+……+26=127;最小的负数,同理,为1 1111111,即==-127==。
    到这里可能有小伙伴开始纳闷了明明是-127那怎么变成-128了呢。
    在这里插入图片描述

    那我们重新来次。
    1、负数的绝对值是反码,byte为一字节8位,最高位是符号位,即最大值是01111111,因正数的补码是其本身,即此正数为01111111十进制表示形式为127
    2、最大正数是01111111,最小负数11111111的反码10000000
    3、因为负数的补码是其绝对值取反,即10000000为最小负数的绝对值,这个1既是符号位也是数值位,而10000000的十进制表示是128,所以最小负数是-128
    4、由此可以得出byte的取值范围是-128到+127
    同理可以推出short和int等。。。。

    在计算机中程序都是按照补码运行的。而且0有+0和-0两种。

    知识拓展

    在计算机内,定点数有3种表示法:原码、反码和补码。
    所谓原码就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
    反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
    补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
    表示方法:
    1、原码的表示:在数值前直接加一符号位的表示法。
    2、反码的表示:
    (1)正数:正数的反码与原码相同。
    (2)负数:负数的反码,符号位为“1”,数值部分按位取反。
    3、补码的表示:
    (1)正数:正数的补码和原码相同。
    (2)负数:负数的补码则是符号位为“1”。并且,这个“1”既是符号位,也是数值位。数值部分按位取反后再在末位(最低位)加1。也就是“反码+1

    展开全文
  • 大家都知道占2个字节的int类型,取值范围是-128~127;那么这个-128究竟是怎么呢? 正文 以java语言中的int类型为例,int占用2个字节byte,共8个bit;也就是8个0或者1来表示正数;在计算机系统中规定第一位表示...

    引言

    大家都知道占2个字节的int类型,取值范围是-128~127;那么这个-128究竟是怎么来的呢?

    正文

    java语言中的byte类型为例,byte占用1个字节byte,共8个bit;也就是8个0或者1来表示正数;在计算机系统中规定第一位表示正负;所以有如下现象:

    0000 0000 ~ 0111 1111 表示正数(十进制:+0到+127)
    1000 0000 ~ 1111 1111 表示负数(十进制:-0到-127)

    由于计算机采取二进制补码来表示负数,所以有
    (原码取反+1得到补码(注意:取反不包括符号位))
    1000 0000 的补码为 0000 0000 ;
    而+0用原码表示也是 0000 0000;
    也就是说,+0和-0在二进制系统中存储的编码时一样的

    因为我们知道,8位二进制可以表示28个编码,但是当用补码表示负值时,这8个bit就只能表示28-1个编码了(换句话说有一个编码:1000 0000,他的补码和另外一个编码重复了。。。)

    由于任何一个原码转变为补码时都不会变成1000 0000;
    所以,人为规定1000 0000这个补码编码对应的十进制数**-128**

    综上,补码系统中,javaint类型表示的取值范围为:-128~127

    (为了找这个人为,肝掉两小时)

    上述内容如有不妥,看官一定私信或评论指正啊!

    参考文章:
    https://www.cnblogs.com/hxh88/p/9284049.html
    https://blog.csdn.net/linux12121/article/details/51236654
    https://blog.csdn.net/cyhleo/article/details/6849704

    相关背景知识

    1. 负数在计算机中是以补码表示的
    2. 补码就是:原码取反+1;
    3. 反码:就是0变1;1变0;
    4. 模:指一个计量系统的计数范围;例如时钟的模是12,超过12就会溢出;12这个值也在计量器上显示不出来,计量器只能显示模的余数(0,1,2,3。。。。11)
    5. 计算机减法系统比较复杂,而加法器比较容易实现,所以如果可以用加法替代减法的话,然后使用同一种电路就可以实现整数的加减法运算了。
    6. 例如在4位计算机中,模是16;5-3=2的结果和5+16-3=16+2=2的结果一样;把二进制负数用补码表示也是为了算减法时直接+这个负数就可以了

    疑问:人为规定是如何实现的 ?

    展开全文
  • java里有数字long来表示整数,如果两个数字的范围超过了long,要做加法算法怎么做呢?这个问题在面试中经常碰到,如果之前没有经历,可能一时有点想不起来怎么做。下面我们来分析一下,两个数字超过了long...
  • Java位运算按位运算移位运算int类型取值范围是多少? 二进制中负数怎么表示? 在进行位运算之前,先看看负数二进制形式在计算机中是如何表示的,在计算机中所有数字都是以二进制补码形式表示的,其中第一位...
  • 今日份知识更新,即《深入...指针转换二、显式转换隐式转换基本类型转换整形提升表达式计算时,整型会首先提升到int类型,当int类型表示的范围不够时,会提升为unsigned int类型。c语言中可以进行整型提升包括boo...
  • 原码就是原来的表示方法 反码是除符号位(最高位)外取反 补码=反码+1 1个字节它不管怎么样还是只能表示256个数,因为有符号所以我们就把它表示成范围:-128-127。它在计算机中是怎么储存的呢?可以这样理解,用...
  • 明明float的表示范围更大怎么会丢失精度呢? 问题深究下来就关系到了浮点数的存储方式, 这里复习下计算机组成的课本内容, 也给不知道的朋友学习下   编程中用到的浮点数就是float和double, 长度分别是32位和64位,...
  • 没详细看协议4个字节CDIRStartIndex超出INT 范围怎么弄, 这里提供一个计算方法; CDIR偏移位计算算法: 一、 小于2G 不会溢出   CDIRStartIndex = CDIRStartIndex;    二、大于2G 会溢出   CDIRStartIndex ...
  • int 转换成byte 数字

    千次阅读 2016-11-25 16:30:57
    int转换为byte溢出怎么计算结果?如 int a=135 转换为 byte 要汉字描述 byte是1个字节 所以(字节型,占1 字节,表示8 位正整数,范围0 ~ 255) int是4个字节 而把int转换成byte会截取最后一个字节 比如你说...
  • 补码计算方法

    千次阅读 2019-05-08 21:54:12
    ​​很基础知识,但是确实很多人并不知道怎么计算,总结了下,可以收藏,需要时候看下。 与编程息息相关 学习目标: 在vc++6.0中int类型所能存储数字的范围是多少 int类型所能存储最大正数用十六...
  • 那么一个byte表示的二进制应该为0000 0000 -1111 1111,又因为最高位代表符号位,那么一个byte表示的范围就应该为(-2^7-1)-(2^7-1)即-127到127怎么会有-128呢?其实也没有什么好说,这就是规定,包括short,int,...
  • 根据标记从后往前比较相邻两数据,若前者小于(默认为小于)后者,标志前者为X1(位置PX)表示将被替换,再次重后往前搜索第一个不小于X1数据,标记为X2。交换X1,X2,然后把[PX+1,last)标记范围置逆。完成。 ...
  • 小数运算需要注意什么? 1. 生活中0.1+0.2=0.3, 计算机中可不是这样,为什么呢?...那么有限的范围怎么表示无限数据呢? 告诉你表示不了,只能存储一个无限接近数。 另外大家都知道计算机所有数据都是二...
  • 一个int类型整数在计算机内由4个字节存储,表示的范围是0~2^32,而实际上,如果一个系统中,用到整数的范围都比较小,高位补0那些字节是否有些浪费了?比如int型整数128,它在计算机内存储为0000 0000 0000 0000...
  • 11Power数值整数次方

    2018-02-25 20:34:17
    题目描述 给定一个double类型浮点数base和int... * 计算机内表示小数时会有误差,判断两个小数是否相等,只能判断它们之差绝对值是不是在一个很小的范围内 * @author LemonLin * @Description :Power11 * @d
  • java常用工具类使用

    热门讨论 2012-03-19 20:11:37
    LONG 比medium更完整的表示方式,比如:2009年8月20日 FULL 综合的表示方式,比如:2009年8月20日 星期四 表3 DateFormat的四种表示格式 因为不同国家地区需要格式化的结果不同,Locale类的对象表示了不同的区域,...
  • 5.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 地址0上到底有什么? 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 5.19 如何访问位于机器地址0处的中断向量?如果我将指针值设为0,...
  • 5.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 61 地址0 上到底有什么? 61 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 61 5.19 如何访问位于机器地址0处的中断向量?如果我将...
  • 《你必须知道495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    内容简介 《你必须知道的495个C语言问题》以问答...5.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 61 地址0 上到底有什么? 61 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 61 5.19...
  • 参考博客: 博客1 博客2 ...解题思路:博客2解题思路容易理解,但是暴力法上限为100000,在博客1...另外,在计算v值时,不用把真实计算出来,因为t最大值达到10100000,超过int表示范围,此处做一个trick...
  • 引言 : int最大能表示的数约在10^9,最大long long也只能存储约在10^19范围数。那怎么进行大数运算呢,拿起草稿纸,做一个加法运算,看看会有哪些步骤。 题解 : 用字符数组来存储大数,每一位当做一个...
  • key、散列函数、value, key 通过散列函数计算得到 value 存储位置</li><li>设计散列函数</li><li>控制散列表装载因子,初始大小和动态扩容策略</li><li>有效解决散列冲突</li><li>对一个工业级散列表...
  • Java类型转换(面试题)

    2020-10-21 17:56:14
    题目 byte b = 130; 此表达式有没有问题? 如果想正确赋值, 可以怎么做? 最终结果是多少?...已知130默认为int类型, Java int类型在内存中占四个字节, 所以int类型130用二进制表示为: 00000000 00000000 0
  • 你必须知道495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    3.2 使用我编译器,下面代码int i=7; printf("%dnn", i++ * i++); 返回49?不管按什么顺序计算, 难道不该打印出56吗? . . . . . . 13 3.3 对于代码int i = 3; i = i++; 不同编译器给出不同结果, 有为 3, 有...

空空如也

空空如也

1 2 3
收藏数 56
精华内容 22
关键字:

怎么计算int的表示范围