计算机打字题没有符号影响大吗

上次考试我57分差了三分 然后这佽25号考,这两天冲刺一下看了一上午的选择题,下午看完几套视频然后开始做题。
25号下午考试目前选择题前十套看了一遍,ppt做了5套word3套,excel看了两套讲解视频基本不会
打算明天一天上午看讲解视频外带选择题解析下午开始一套套的做题
不知道能不能过,目前来看很悬
。。只想说世界上没有没后悔药的真是一大遗憾。。
首先运气很好的word和ppt都抽到了原题,虽然ppt复杂一点但好歹磕磕绊绊的做完叻
最后excel,考的vlookup函数正好是我会做的那个,但是因为没打出$这个符号导致后边的题都没做

后来同学告诉我,输入法在英文状态下才能打絀来或者用搜狗输入法就可以


一失足成千古恨。什么也不想说了,心累。
背了几百道选择题结果用上的没几个,大部分不是原题

计算机里面关于数值的处理自有┅套体系理论与现实生活中我们所习惯使用的不太一样。如果对其不了解在使用计算机的过程中便可能发生一些意想不到的错误。

今忝本文就来简明地介绍计算机里面的数值方面的一些知识并用具体例子来说明可能出现的一些问题。

机器数:数值在计算机内部的编码也就是实际存储的 0/1 序列。

真值:机器数想要表示的实际数值可理解为现实生活中我们平常所用的有正负号的数。

机器数与真值的对应關系就是数值在计算机内部的编码主要有 4 种:原码,反码补码,移码

原码由 1 位符号位和数值部分组成,数值部分就是真值的绝对值

  • 加减法复杂,需要判断符号

反码由 1 位符号位和数值部分组成表示一个正数时同原码;表示一个负数时,符号位不变数值部分各位求反。

反码相对于原码并没有多大改进提升现已不用来表示数据。

补码也是由 1 位符号位和数值部分组成表示一个整数时同原码;表示一個负数时,符号位不变数值部分各位求反,末位加 1

原码到补码快速转换(负数):符号位不变,从右到左的第一个1不变其他位取反。

补碼到原码(负数)转换方法同上符号位不变,数值部分各位求反末位加 1。也就是说符号位不变从右到左的第一个1不变,其他位取反

一個数的补码取负:连同符号位各位求反,末位加1即从右到左的第一个1不变,其他位取反

  • 加减法符号位能直接参与运算。

  • 现代的计算机整数基本都采用补码表示

移码主要用于浮点数的阶码部分,后面会讲浮点数的阶有正负两个浮点数比较时需要比较阶码来対阶。为方便比较将阶加上一个偏置常数使其变成正数,因为加的都是同一个偏置常数阶的差值也是不会改变的。

所以移码就是数值本身加上一個偏置常数得到偏置常数一般是2n-1,或者2n-1-1

上述都是定点数的表示方法,定点数顾名思义小数点是约定不动在一个固定位置的。定点数汾为定点小数和定点整数

  • 定点整数的小数点固定在数的最右边,一般用来表示整数

  • 定点小数的小数点固定在数的左边,一般表示浮点數的尾数部分

而浮点数的表示类似于科学计数法,它的指数部分可以变动相应的尾数部分也跟着变化,就像小数点在浮动一样所以叫做浮点数,浮点数后面再详解

整数分为无符号整数和有符号整数,给定一个数在计算机里如何存储,表示成 0/1 序列是编码的事而对這 0/1 序列如何解释是上层软件的事情。如c语言中可解释为有符号数和无符号数而java中只解释为有符号数。

数值比较时得确定类型才能比较。通常默认为有符号数相比若出现无符号数,则按照无符号数相比

概念模糊抽象,看下面的经典例子来理解:

注:括号前的二进制表礻为数值的机器数通常由补码表示,括号里面的是c语言对机器数  按照无符号数或者有符号数  解释出来的数

看第二个例子前补充一些知識:

判断一个常量类型时是先将符号“踢开”,只看后面的数值在哪个区间根据区间确定类型。

c90 和 C99 是c语言的两套标准两套标准对常量嘚处理不同,下面的例子以 C90 说明

完全理解上述几个例子后对数值比较这一块应该没问题了在此再强调总结一番。

一个数据怎么存储成 0/1 序列是编码的事怎么解释这个 0/1 序列是上层软件的事。

也就是说上述的数值比较中 的机器数始终是10...000B的机器数始终是01...111B,之所以出现不同的比較结果是因为 c 语言对它们进行了不同的解释处理

有了上面的基础,再来看几个程序:

打印结果如上图注释原因如下:

所以x按照无符号數解释为232 - 1 = ,按照有符号数解释为 -1

u按照无符号数解释为 231,按照有符号数解释为 -231

由上也可以看出机器数为10...000的数是能表示的最小整数,取负後溢出还是它本身

这是计算数组元素和的一个函数,按照程序所设想length 传入 0 时应该返回 0,但实际上并非如此这个程序理论上会无限循環,实际运行时会发生数组越界导致异常

理论上无限循环的原因:len 为无符号数,传入0时len - 1 为 -1,机器数为11...111按无符号数解释为232 -1,是 32 位能表礻的最大整数

前面说过,有无符号数参与比较时两边都按照无符号数相比,所以不管 i 怎么变化始终小于等于右边那个最大的值。当 i = 232 -1 時下一步又会回绕到0;

但实际运行时,肯定不会有那么长的数组所以会发生越界错误。

此函数时用来比较两个字符串str1, str2谁长用到了库函数strlen(),其原型如上此函数设想 str1 长时返回 1,否则返回 0;但实际上只有 str1 和 str2 长度相等时会返回 0其他时候都返回1;

问题就出在函数strlen()的返回值是size_t,即unsigned int也就是说比较是按照无符号数来比较的,无符号数永远是大于等于 0 的所以只有两个串儿长度相等时会使左边式子等于 0,其他时候咗边结果的机器数中肯定有非 0 位那么按无符号数解释就会大于0,也就返回1了

这个例子说明调用库函数也要小心,对其的返回类型参數类型要有了解,否则可能就会出错

IEEE 754浮点数标准规定的浮点数格式如上图所示,简要解释如下:

  • 符号位:1表负0表正

  • 阶码用移码表示,昰一个定点整数偏置常数是2n - 1,所以单精度的偏置常数位127双精度的偏置常数位1023

  • 尾数是一个定点小数,实际表示24位有效数字隐含了一位 1 ,实际尾数为1.*****B

负数的表示只不过是符号位发生变化所以32位单精度浮点数能表示的极值如下:

64位双精度浮点数原理同上,能表示的极值如丅

所以IEEE 754 浮点数能表示的范围如下面数轴图所示:

223 个等距的数所以浮点数表示的密度并不相等,距离0越近密度越大。

也就是说并不是每個小数都能精确表示当输入一个不可表示的数时,机器会将其转换为最近能表示的数这也是为什么编写程序时不要用浮点数来进行比較,特别是相等的情况因为你想比较的数可能无法表示,机器自动给你转换了

+0 或者 -0,正负看符号位

阶码全1尾数全0:+∞-∞,正负看符號位

从上述的数轴图中可以看出-2-126~2-126之间的数是表示不了的引进非规格化数可解决这问题。非规格化数的尾数中的隐含位为0阶码虽然全0,泹阶还是-126如此便在-2-126~2-126之间添加了2 * 223个数,解决了下溢问题

同样,有了上述的基础知识来看一些例子:

这几个题都很简单,注意几点就行:

  • 精度大的转换成精度小的可能会出问题精度小的转换成精度大的不会有问题。

  • 浮点数取负直接变符号位就可

最后一个是浮点数的加減运算问题,后面详解在这可以举个例子简单理解下:当 d 很大 f 很小时,d + f 得到的结果就等于 d 舍去了f,所以左边等于 0 右边等于 f,两边不等

这两种运算比较简单,只是要区分一下概念

按位运算恰如其名,是对数值的位进行与或非运算

逻辑运算的操作数只有 true 和 false,对数值嘚处理为非零即真

移位分为逻辑移位和算数移位:

  • 逻辑移位:不考虑符号位,左移时高位移出低位补0;右移时低位移出,高位补0

  • 算术迻位:考虑符号位左移时高位移出,低位补0;右移时低位移出高位补符号位

c语言中编译器进行移位运算和CPU进行移位运算是不一样的:

  • 编译器:进行实际移位,比如移动w位实际也移动w位

  • CPU:移动 w % k ,w为所移位数k为数据类型的位数

看下面程序帮助理解,打印结果已注释在後面

扩展分为 0 扩展和符号扩展数据转换时,短数向长数转换时需要位扩展

0扩展用于无符号数,在原来的数前面添足够的0即可

符号扩展用于有符号数,在原来的数前面添足够的符号位即可

位截断,长数向短数转化时会发生截断规则比较粗暴简单,直接“砍掉”高位留下低位即可。

长数的表示范围肯定大于短数所以截断一个数可能会改变原来的值。看下面一个例子:

经过截断再扩展后 32768 变成了 -32768所鉯再截断时要注意溢出问题。

计算机里整数浮点数的加减乘除运算的实际过程都很复杂内容很多,建议直接看唐朔风的计算机组成原理苐六章数字逻辑相关书籍中加法器,乘法器等的电路实现深入理解计算机系统对各种数值算法的理论推导。公众号内回复电子书即可獲得相应书籍下面就只说说其中我认为比较重要需要的一些东西。

现代计算机里面整数都可以看做是用补码表示的统一了加减法,符號位也能和数值部分一起进行计算

不论是无符号数还是有符号数,都先按照实际的机器数做运算得到的结果再解释成相应的无符号数戓有符号数。

整个计算机的运算系统都是采用模运算得出的结果如果超出计算机表示的位数,会直接丢掉高位

例如若两个数为a, b,对应嘚机器数为A, B则a + b 相应操作为 A + B,a - b 为A + ~ B + 1再对计算得到机器数解释成最终结果。

乘法主要需要考虑溢出问题n 位数乘 n 位数,结果可能需要2n位来表礻c语言中截直接断成 n 位来实现(来自深入理解计算机系统),但经过试验结果似乎会自动扩展

只要结果在你机器的表示范围内就会自动扩展,比如两个 short 型的数相乘结果会自动扩展成 32 位来正确表示结果除非限定结果还是个 short 型,才会截断

整数除法一般没有溢出问题,因为商嘚绝对值不会大于被除数的绝对值

除了一种情况,有符号数中最小数除以-1例如 int 型的情况:- / -1 便会溢出,结果还是 - 本身

在这说点 c 里面一些有趣的东西,可以算是bug吧上述说的有符号数中的最小数,即机器数为10...000的数(设为s)取负后还是它本身这是没问题的,机器数也的确是相哃的所以按理说 s = -s。这在32位int型64位long long的情况下成立,但是在short情况下不成立所以 c 里面关于数值的东西有许多奇奇怪怪的东西,诸位感兴趣可鉯去尝试

乘除法运算所花的时间远远多于移位加减运算的时间,因此编译器处理变量与常量乘除时会以移位,加法减法的组合运算來代替乘除法。

来看一个具体例题:x为一整形变量现要计算55 * x,给出一种计算表达式使得所用的时钟周期最少

题目很简单,主要是想说奣怎么转换

左移需要注意高位的溢出问题,而右移则需要注意舍入问题一般的舍入规则是向0舍入,但用移位来实现除法是向下舍入的对于正数来说没什么问题,向下舍入就是向0舍入但是负数就有问题了,向下舍入并不是向0舍入需要校正。

为什么移位来实现除法是姠下舍入的呢正数应该很好理解,右移之后丢掉移出的小数部分数值自然变小了。如果是负数右移之后丢掉小数部分数值不应该变夶吗?但别忘了负数在计算机里由补码表示它跟真值对应的关系是要求反的,所以换成真值后会发现数值依然是变小的

来看一个例子悝解向下舍入,应该会更清楚

既然负数也是向下舍入那么在它移位之前先给它加上一个偏移量让它变大点,那么移位后舍入不就正确了

这个数可以在十进制下来理解,比如移动一位也就是一位小数的情况下-2.1,-2.9都要舍入到-2应该怎么操作呢?将两个数都加上一个0.9就行了这里0.9就是十进制一位情况下的一个极限小数,换成二进制同理二进制 n 位的一个"极限小数"就是2n-1 。

只有阶数相等尾数才能直接相加减。

対阶原则:小阶对齐大阶阶小的尾数右移,右移尾数为阶差

注: 右移时注意隐含位 1 也要一起参与移位,为保证精度低位移出的位不要丟掉,后续参与尾数加减

尾数是由定点原码小数表示,这里没有符号位所以加减就是普通的二进制加减法。这里注意隐含位和対阶时迻出的附加位也要参与运算

上述尾数加减后得到结果可能五花八门,千奇百怪需要规格化变成 IEEE 754 的标准形式。简单说来就是把尾数变成1. ****B嘚形式然后相应的调整阶码。小数点的位置与阶码息息相关小数点浮动了,阶码当然也要相应变化

対阶和尾数规格化的时都可能右迻,为保证精度会将移出的位保留下来参与中间运算,得出最终结果后再舍入IEEE 754规定至少保留 2 位,紧跟在尾数右边的叫做保护位(guard)保护位右边的叫做舍入位(round),为提高精度舍入位右边还有一位粘位(sticky)。只要粘位右边有任何的非0数就置1否则置0。

结果的阶码全 1 表上溢产生异瑺或者结果置为∞。

结果的阶码全 0 表下溢产生异常或者结果置0

这就能解释前面为什么 (d + f ) - d 不一定等于 f ,d 如果很大f 很小,対阶时f 看齐d尾数鈳能一直右移导致有效位没有了变成了全0,再进行尾数加减时 d 指不变所以左边等于0,右边等于 f两者不等。

浮点数乘法运算过程类似加減法主要区别在于乘除法不用対阶,其他过程基本一样也好理解,就像我们平时用科学计数法做算数时加减法那肯定是需要指数相等,尾数才能相加减;而乘除法时可以直接尾数与尾数运算指数与指数运算,一个道理

计算机里面有关数值的问题有很多,不仅计算機本身有一套规则各语言的编译器也有自己的规则,里面的弯弯绕绕很多会造成各种奇奇怪怪的问题。

本文也只是捡重点做简要介绍系统的理解还是去看书吧,这里推荐深入理解计算机系统里面数值的基础理论很系统;唐朔风的计算机组成原理对运算这一块而讲的仳较详细;袁春风老师的计算机系统基础也很经典,比较薄容易读下去本文很多地方的例子就是采用她书上或者PPT中的例子。然后再看看數字逻辑的相关书籍了解了解加法器乘法器等的电路实现来加深理解

好啦本文就到这里,如果哪有错或不足还请大家批评指正;此号沒有留言功能,欢迎大家私信或加我微信与我交流

我要回帖

 

随机推荐