整型数据运算#
无符号加法#
对于两个由w位二进制数组成的非负数字x和y,0≤x,y≤2w−1 。
当我们计算这样两个无符号数之和时, 0≤x+y≤2w+1−2,出现了需要用w+1位二进制数表示的情况。
这时的解决方法是截掉最高位,变回w位二进制数,相当于在结果数值上减去2w,即如下情况:
x+wuy={x+y,x+y−2w,x+y<2w2w≤x+y<2w+1补码加法#
与无符号加法原理类似,对于两个w位二进制数补码组成的的x,y,−2w−1≤x,y≤2w−1−1。
两个补码之和的范围则有−2w≤x+y≤2w−2,变成了需要由w+1位二进制数表示的情况。
同样地,截掉最高位,但由于补码最高位具有的性质,导致转换成十进制数值时出现了三种可能性:
x+wty=⎩⎨⎧x+y−2w,x+y,x+y+2w,2w−1≤x+y−2w−1≤x+y<2w−1x+y<−2w−1判断补码加法的溢出:将x+y与x,y分别与0进行比较,x,y<0且x+y≥0,或x,y>0且x+y<0时溢出,否则无溢出。
补码取反:
−wtx={TMinw,−x,x=TMinwx>Tminw十六进制数取反:
首先将十六进制数转化为十进制数,因为取反判断依据为十进制数值与Tminw的大小关系。判断十六进制的数值是否超出TMaxw,若溢出,则转化为二进制数后截掉最高位,后转化为十进制数值;若未溢出,则直接转化为对应数值。
随后再按照补码取反的规则进行取反。
最后将十进制数重新转化为十六进制数,正数保持不变;若为负数,首先求该负数的相反数的原码,再取所求原码的补码,最后加上一,所得的二进制数按照无符号数解读,则为最终的十六进制数。
详情见书P95练习2.23.
无符号乘法#
对于两个由w位二进制数组成的非负数字x和y,0≤x,y≤2w−1 。
这样两个数的乘积的范围有0≤x∗y≤(2w−1)2,需要用2w位的二进制数进行表示。
处理方法是对2w取模,即截断为w位。
x∗wuy=(x∗y)mod2w补码乘法#
对于两个w位二进制数补码组成的x,y,−2w−1≤x,y≤2w−1−1。
这样两个数的乘积的范围有−22w−2+2w−1≤x∗y≤22w−2,需要用2w位的二进制数进行表示。
处理方法与无符号乘法类似,截断为w位后从无符号转化为补码。
x∗wty=U2Tw((x∗y)mod2w)和常数的乘法#
首先,某个整数x乘以2k可以等价将x的二进制数左移k位,并将该x按照对应编码的解读方式进行运算(即按照补码或是无符号方法进行解读)。
又已知任意一个十进制数可以由二进制数进行表示,故在乘以其他整数时,可以转化为若干次左移运算的求和:
N=(2a1+2a2+…+2am)x∗N=x∗(2a1+2a2+…+2am)=(x<<a1)+(x<<a2)+…+(x<<am)例如:
x∗11=x∗(23+21+20)=(x<<3)+(x<<1)+(x<<0)除以2的整数次幂#
首先注意,除以2k不完全等同于右移k位,尽管在无符号数的案例中的效果是相同的,但是在处理补码中的负值的除法时,两者有一些舍入上的微妙差异。
右移k位的舍入方法总是为向下舍入,即数值为正时去除小数点部分,数值为负时去除小数点部分并且减去一,即:
x>>k=⌊x/2k⌋补码的负数在除以2k后的舍入情况为向0舍入,即舍入方向均为向0靠近:
x/2k={⌊x/2k⌋,⌈x/2k⌉,x≥0x<0在处理负值的舍入时,并不能单纯视作右移k位,需要进行向上舍入的操作。换言之,除法与右移k位的等价关系即为:
x/2k={x>>k,(x+(1<<k)−1)>>k,x≥0x<0
浮点数#
小数的二进制表示#
对于任意整数bmbm−1…b2b1b0.b−1b−2…b−n+1b−n,整数部分的二进制数bmbm−1…b2b1b0等同于∑2i∗bi,与之类似地,小数部分的二进制数b−1b−2…b−n+1b−n,代表着∑2i∗bi。
与十进制中无法用有限位小数31类似,二进制中只能用有限位小数表示那些能写成x∗2y的数字,而那些不能被表示成这种形式的小数,则需要用类似的循环小数进行表示,如表示51:
二进制表示形式 | 对应分数数值 | 对应十进制数值 |
---|
0.02 | 20 | 0.010 |
0.012 | 41 | 0.2510 |
0.0102 | 82 | 0.2510 |
0.00112 | 163 | 0.187510 |
0.001102 | 326 | 0.187510 |
0.0011012 | 6413 | 0.20312510 |
0.00110102 | 12826 | 0.20312510 |
0.001100112 | 25651 | 0.1992187510 |
IEEE浮点数表示规则#
与十进制数的科学计数法类似,在二进制中,可以将V以2为基数进行科学计数法的表示:
V=(−1)s∗M∗2E在公式中:
- S是符号位,在二进制表示中占第一位,S=0时代表正数,s=−1时代表负数。在二进制表示中占首位。
- M是尾数,在32位的二进制表示中占23位,64位的二进制表示中占52位。由frac=fn−1…f1f0表示,但并不完全等同于M。在不同的情况下取值范围有(0,1−ϵ]与[1,2−ϵ)两种情况。
- E为指数,exp=ek−1…e1e0是E的编码,在32位中占8位,64位中占11位,但exp不等同于指数,需要通过偏置操作后才能转化为E。
在存储方式上,尾数M排在exp的后面。目的是为了便于进行比较浮点数的大小,通过直接比较指数的不同便能较快的得出大小关系。
浮点数分为三种。
Normalized Values#
这一类的浮点数的exp不全为1或不全为0,而E=exp−Bias,其中的Bias=2k−1−1,为一定值。
规定M=1+frac,M∈[1,2)。由于保留的整数部分只能为1,故可以省略整数部分的1位,用于增加小数点部分的一位精度。
Denormalized Values#
这一类的浮点数的exp=0,规定此时E=1−Bias,M=f,与前一类有所差别。
这一类浮点数的定义有两类用途,当frac部分全部取0时,可以用来表示0.0,特别地,S=1,其余为全取0时,能够获得−0.0,这两者在有些方面有所差别,但在其他方面类似(书上未展开说明);frac部分不全为0时,还能用来表示非常接近0.0的数。
Special Values#
第三类浮点数的exp每一位都取1,用于表示一些特殊定义。
S与frac全部取0时,可以用来表示∞,S=1而frac全部取0时,用于表示−∞。特别地,1.0/0.0=∞,1.0/−0.0=−∞。
frac不全为0时,代表NaN,在一些没有定义的计算中会输出这一结果,如−1、∞−∞。
浮点数的舍入#
浮点数的舍入通常情况下为向偶舍入,在该数小于中值时向下舍入,大于中值时向上舍入,等于中值时向最近的偶数舍入。
二进制数字的舍入情况(保留一位小数):
舍入前 | 舍入后 | 舍入情况(向偶舍入) |
---|
10.0102 | 10.02 | 向下舍入 |
10.0112 | 10.12 | 向上舍入 |
10.1102 | 11.02 | 向上舍入 |
11.0012 | 11.02 | 向下舍入 |
简言之,保留位数的后面若为10…0(最高位为1,其余为0)的形式,则需要让保留后的最低有效位数为0;若除去最高位外仍有若干个1,则向上舍入;最高位不为1,则向下舍入。
按照十进制数值转化为IEEE浮点数表达形式的方法:
首先将十进制小数写成二进制表达式,后表达为二进制的科学计数法,即形如M∗2E的式子。
根据题目给定的frac部分位数进行判断,若超出给定位数则进行舍入,不超出则保留,最终结果即为frac部分的二进制数。
根据exp=E+Bias,可求出exp部分的值,按照二进制代码展开,即为exp部分的二进制数。
详情见书P122 练习2.52.
浮点数运算#
对于两个浮点数,其加法为:
(−1)s∗M∗2E=(−1)s1∗M1∗2E1+(−1)s2∗M2∗2E2其中的s,M需要对齐小数点,再分别做加法,E即为对齐后的E1。
加法性质:
- 封闭(包括NaN):集合中任意两个元素a,b通过运算f得出的结果仍在集合中
- 满足加法交换律
- 加法结合律不成立
- 0的性质成立:任意一个数加上0仍然为其本身
- 相反数存在(∞和NaN除外)
- 单调性成立(∞和NaN除外):a≥b⇒a+c≥b+c
其乘法为:
(−1)s∗M∗2E=(−1)s1∗M1∗2E1∗(−1)s2∗M2∗2E2其中s=s1+s2,M=M1∗M2,E=E1+E2。
乘法性质:
- 封闭
- 乘法交换律成立
- 乘法结合律不成立
- 1的性质成立:任意一个书乘以1仍然为其本身
- 乘法分配律不成立:a∗(b+c)=a∗b+b∗c
- 单调性成立(∞和NaN除外):a≥b⋃c≥0⇒a∗c≥b∗c
- 若运算后的M≥2,则将其右移并且增加E。
- 若E超过范围,则溢出。
- 若E未超过范围,则舍入M,计算得到frac。
注意事项#
运算后若M≥2,则右移并增加E。
若E超过范围,则溢出;若未超过,则舍入M,并计算得出frac。
关于溢出:
- 若E超过上界,则上溢(Overflow),表示为∞
- 若E低于下界,则下溢(Underflow),显示为0
C语言中的浮点数#
C语言中,浮点数的数据类型有float和double两种,它们与整型int的类型转换会改变位表示。
double/float→int:类似于向0舍入(超范围未定义,通常设为TMin)
int→double:由于float的整数部分与小数部分能够表示的范围更大,故能够精准转换
int→float:数字不会溢出,但是会根据规则舍入