不同进制数之间的转换:
十六进制加减法可以选择把十六进制(0--F)换成我们熟悉的十进制来进行计算,但是比较麻烦,这里推荐直接使用十六进制进行计算。只要将执行十进制加法和减法所使用的方法改成以十六进制为基数就好了。 借一当十六,逢十六进一。
A.0x503c+0x8=
c+8=0x14(c往后数8就好了)
所以答案为0x5044
B.0x503c-0x40=0x4ffc
从第三位借一,即借了16,16+3-4=15->f
第三位为0,则第三位向前借一,当16,再被借1,剩下15->f
C.0x503c+64=
64->0x40,即0x503c+0x40
结果为0x507c
D.0x50ea-0x503c=
可看作ea-3c=0xae
布尔运算,C 语言中的位级运算、逻辑运算和移位运算:
位级运算
取反(NOT):1->0,0->1与(AND):1&1=1,1&0=1,0&0=0(有0为0)或(OR):1|1=1,1|0=1(有1则1)异或(EXCLUSIVE-OR):1^0=1,1^1=0(不同为1)
![]()
~a=[10010110]
~b=[10101010]
a&b=[01000001]
a|b=[01111101]
a^b=[00111100]
逻辑运算逻辑运算符:||、&&、!在逻辑运算中,我们认为所有非0的参数都为True,返回1,为0的参数为False,返回0.所以我们在做题的时候要看清楚,是位级运算还是逻辑运算。
如果为逻辑运算,那么输出来的要么是0要么是1.除此之外,我们还要注意逻辑运算符与位级运算还有一个不同,如果对第一个参数求值已经可以确定整个逻辑运算的结果,那么逻辑运算符将不会对第二个参数求值。比如A&&B&&C,如果A=0,那么后面的B、C我们不予计算再如A||B||C,如果A=1,那么后面的B、C我们同样不予计算
![]()
x=0x66(2+4=6),y=0x39(1+2=3,1+8=9)
变为二进制,则x=0110 0110,y=0011 1001
x&y=0010 0000=0x20
x|y=0111 1111=0x7f
~x|~y=(1001 1001)|(1100 0110)=1101 1111=0xdf
x&!y=(0110 0110)&(1100 0110)=0x00
x&&y=0x01
x||y=0x01
!x||!y=0x00
x&&~y=0x00
移位运算
左移(逻辑和算术一样)左移,往左移动,后面补0右移逻辑:往右移动,前面补0算术:注意符号,第一个为符号位,右移,前面补与符号位一样的值
![]()
0xC3->[1100 0011]->[0001 1000]->0x18->[0011 0000]->0x30->[1111 0000]->0xf0
0x75->[0111 0101]->[1010 1000]->0xa8->[0001 1101]->0x1d->[0001 1101]->0x1d
0x87->[1000 0111]->[0011 1000]->0x38->[0010 0001]->0x21->[1110 0001]->0xe1
0x66->[0110 0110]->[0011 0000]->0x30->[0001 1001]->0x19->[0001 1001]->0x19
补码编码以及有符号数和无符号数之间的转换,理解强制类型转换影响关系运算的结果:
![]()
0x0->[0000]->0->0
0x5->[0101]->1+4=5->1+4=5
0x8->[1000]->8->-8
0xD->[1101]->1+4+8=13->1+4-8=-3
0xF->[1111]->1+2+4+8=15->1+2+4-8=-1
![]()
w=4;
-8<0->(-8)+2^4=8
-3->13
-2->14
-1->15
0->0
5->5
转换:
当执行运算时,如果它的一个运算数是有符号的而另外一个是无符号的,那么c语言会隐式的将有符号数转换为无符号数,并假设两个都是非负的来执行。
![]()
2^32=4,294,967,296,2^31=2,147,483,648
U代表无符号数
右边为无符号数,将左边强制转换成无符号数,两边相等
无符号->1
左右均为有符号数,直接比较
有符号->1
无符号->0
有符号->1
无符号->1(左右均为复数,可以直接进行比较)
![]()
将length定义为int类型,或将i<length
因为length为无符号数,则i会自动进行转换,当length在0到1之间时,length-1为负数,进行转换,为一个很大的数,会出现错误。
![]()
strlen()定义为unsigned int,则我们可以知道,当strlen(s)-strlen(t)小于0时,因为返回的为无符号数,会发生转换,会返回1.
修改为strlen(s)>strlen(t)
![]()
可知:t = x + y时,如果x,y异号(或者存在0),则肯定不会溢出。
如果x,y均大于等于0,则t<0就是正溢出,如果x,y均小于0,则t>=0就是负溢出。
于是,可以利用三个变量来表示是正溢出,负溢出还是无溢出。
int saturating_add(int x, int y){
int w = sizeof(int)<<3;
int t = x + y;
int ans = x + y;
x>>=(w-1);
y>>=(w-1);
t>>=(w-1);
int pos_ovf = ~x&~y&t;
int neg_ovf = x&y&~t;
int novf = ~(pos_ovf|neg_ovf);
return (pos_ovf & INT_MAX) | (novf & ans) | (neg_ovf & INT_MIN);
}
掌握采用移位和加法运算的组合来代替乘以常数因子的乘法:
练习题 2.40
8-2=6
(x<<3)-(x<<1)或(x<<2)+(x<<1)
31=32-1
(x<<5)-1
-6=2-8
(x<<1)-(x<<3)
55=64-1-8
(x<<6)-(x<<3)-x
家庭作业 2.77
17=16+1
(x<<4)+x
-7=x-8
1-(x<<3)
60=64-4
(x<<6)-(x<<2)
-112=16-128
(x<<4)-(x<<7)
IEEE 浮点表示:浮点数格式(符号、阶码、尾数)、规格化的值
课本 P80 图 2-35 的例子
中间五位为e,后面几位为f。
bias=2^(4-1)-1=7
非规格化
E=1-bias,M=f
e=0,E=1-e=-6,2^E=1/64,f=0,M=0
规格化
E=e-bias,M=1+f
e=1,E=e-bias=-6,f=0,M=f+1=1
练习题 2.47
bias=2^(k-1)-1=1
接码域全是0,为非规格化数。
前四个为非规格化数
0 00 00 ->0->1-1=0->1->0->0->0->0->0
0 00 01->0->1-1=0->1->1/4->1/4->1/4->1/4->0.25
0 00 10->0->1-1=0->1->2/4->2/4->2/4->2/4->0.5
0 00 11->0->1-1=0->1->3/4->3/4->3/4->3/4->0.75
接下来是规格化数
0 01 00->1->1-1=0->1->0->1->1->1->1
0 01 10->1->0->1->1/2->3/2->3/2->1.5
0 01 11->1->0->1->3/4->7/4->7/4->1.75
0 10 00->2->1->2->0->1->2->2
0 10 01->2->1->2->1/4->5/4->5/2->2.5
0 10 10->2->1->2->1/2->3/2->3->3
0 10 11->2->1->2->3/4->7/4->7/2->3.5
家庭作业 2.85
bias=2^(k-1)-1
V=2^E*M
A.7=1+2+4
111 000=1.11*2^2 M=1.75 V=7-->E=2
E=e-bias->e=E+bias=E+2^(k-1)-1=2^(k-1)+1
位表示为s-e-f 0-10...01-1100...0
B.最大奇整数,M=1.1111,f部分全部为1,E=n,在2^(k-1)>=n情况下成立
值为2^(n+1)-1
位表示 0-1111-1111
C.最小规格化数为2^(1-bias)=2^(-2^(k-1)+2),倒数为2^(2^(k-1)-2),M=1,f=0,E=2^(k-1)-2,e=bias+E=2^(k-1)-2+2^(k-1)-1=2^k-3=2^k-1-2=(前k项2^n之和)-2
位表示 0-111...01-00...0