紫书第1章实验
实验A1:表达式 11111 ∗ 11111 11111\ast11111 11111∗11111的值是多少?改成6个1呢?9个1呢?
以下几个都用有符号整数 % d \%d %d输出结果。
表达式 11111 ∗ 11111 11111\ast11111 11111∗11111的值为 123454321 123454321 123454321。不越界,所以得到了正确结果。
把5个1改成6个1,结果变成了 − 539247567 -539247567 −539247567,原因是,原本的结果是 111111 ∗ 111111 = 12345654321 > 2 31 − 1 = 2147483647 111111\ast111111=12345654321>2^{31}-1=2147483647 111111∗111111=12345654321>231−1=2147483647,产生了越界,所以 i n t int int的32位上的结果是 12345654321 % 2 32 = 3755719729 = 2 31 + 1608236081 12345654321\%2^{32}=3755719729=2^{31}+1608236081 12345654321%232=3755719729=231+1608236081,由 i n t int int负数的补码表示规则,第一位是符号位,所以输出的值为 − 2 31 + 1608236081 = − 539247567 -2^{31}+1608236081=-539247567 −231+1608236081=−539247567,和试验结果相符。
把5个1改成9个1,显然更是越界的,得到的结果是 1653732529 = ( 111111111 ∗ 111111111 ) % 2 32 1653732529=(111111111\ast111111111)\%2^{32} 1653732529=(111111111∗111111111)%232,相符。
如果改成 % f \%f %f,都会输出 0.000000 0.000000 0.000000,这涉及到浮点数的保存方法,由于 % f \%f %f是自动寻64位内存的,所有 i n t int int型的数都在后32位尾数里,都很小, % f \%f %f自动保留6位小数之后都是 0.000000 0.000000 0.000000。
实验A2:把实验A1中的所有数换成浮点数,结果如何?
拿 11111.0 ∗ 11111.0 11111.0\ast11111.0 11111.0∗11111.0为例,如果用 % f \%f %f输出,可以输出正确的结果 123454321.000000 123454321.000000 123454321.000000,因为 % f \%f %f可以表示的数据范围还是挺大的。但是如果改成了 % d \%d %d,结果就变成了 − 272632416 -272632416 −272632416。这个结果是因为 123454321 ≈ 1.83961... ∗ 2 26 123454321\approx1.83961...\ast2^{26} 123454321≈1.83961...∗226,如果是采用IEEE的标准存储,不出意外这应该是尾数的后32位部分。从实验A1和A2我们显然可以明白 i n t int int和 f l o a t float float在printf里显然不可以瞎转换。
用 % d \%d %d输出显然无法得到正确结果,但注意当九个1时,即使用 % f \%f %f输出,结果也会变成 12345678987654320.000000 12345678987654320.000000 12345678987654320.000000,个位出现了1的偏差。究其原因,之前提到浮点数使用幂存储方法, d o u b l e double double类型有53位尾数,而 log 2 12345678987654321 \log_212345678987654321 log212345678987654321刚好是53点几,尾数的精确度是 2 − 52 2^{-52} 2−52,乘上阶数 2 53 2^{53} 253刚好到达个位数量级,所以差不多会开始产生偏差。
实验A3:表达式sqrt(-10)的值是多少?尝试用各种方式输出,在计算的过程中会报错吗?
如果用 d o u b l e double double输出 s q r t ( − 10 ) sqrt(-10) sqrt(−10),会得到nan,即not a number,不会报错。
如果用 i n t int int输出 s q r t ( − 10 ) sqrt(-10) sqrt(−10),又得到了之前神秘的负数 − 272632416 -272632416 −272632416,这应该是一个随机的结果,因为在程序里添加了一段文字之后输出又会变化,其中的转化规则我也不知道,也不重要。因为nan用浮点数表示,阶码部分全是1,小数部分不为0,所以小数部分可以任意取,有很多种。会返回哪一种给 % d \%d %d,我暂时还不知道。
实验A4:表达式1.0/0.0、0.0/0.0的值是多少?尝试用各种方式输出,在计算的过程中会报错吗?
1.0 / 0.0 1.0/0.0 1.0/0.0其实是可以算出来的,用 % f \%f %f输出得到 i n f inf inf,但用 % d \%d %d输出也是一个可变化的结果,我不太理解,照理说 i n f inf inf的浮点表示不是固定的吗?还是这里的浮点数没有采用IEEE的标准?求指教…
0.0 / 0.0 0.0/0.0 0.0/0.0的结果是nan,一般 p r i n t f printf printf输出的时候,能算出来的会输出对应的0或者 i n f inf inf,算不出来的,就是nan。用 % d \%d %d表示的结果就不谈了,也是可变的。
实验A5:表达式1/0的值是多少?在计算的过程中系统会报错吗?
现在可以输出一个随机值,并没有输出 i n f inf inf,因为divided by zero属于系统未定义行为。但我记得以前似乎是会报错的?
实验B1:同一行中输入12和2,并以空格分隔,是否得到预期结果?
可以得到, % d \%d %d会自动寻找整数。
实验B2:在不同两行输入12和2,是否得到预期结果
可以得到,道理同上,该行没有会自动读下一行。
实验B3:在B1和B2中,在12和2的前面和后面插入大量的空格或\t,甚至插入空行
一样可以得到正确的结果。
实验B4:把2换成字符s,重复实验B1~B3
其实换成字符s和打空格没有本质区别,都是一个字符。可以正常输出12,但第二个值就是未定义的了。
思考:如何输出%和d两个字符?
printf("%%d\n");
章末的问题
1. int型整数的最小值和最大值?
-2147483648和2147483647。
2. double型浮点数能精确到多少位小数?或者,这个问题本身值得商榷?
这个问题值得商榷,因为double的精度和前面阶码的大小有关。数据的绝对值越大,精度就越低。
3. double型浮点数最大整数值和最小正数值分别是多少,不必特别精确
如果采用IEEE浮点表示,最小正数是最小的非规格化数,本应该是 2 − 52 ∗ 2 − 1022 2^{-52}\ast2^{-1022} 2−52∗2−1022,但结果却是2的负三百多次方,可能标准变了。。总之差不多在2的几百次方左右。
4.逻辑运算符号“&&”、“||”和“!”的优先级?
查表可知优先级关系是 ! > & & > ∣ ∣ !>\&\&>|| !>&&>∣∣。
5. if(a) if(b) x++; else y++; else和哪个if配套?
尽管说else匹配的是最近的if,但严格说来应该是同一代码块中最近的if。上述语句等价于
if(a){
if(b){
x++;
}
else{
y++;
}
}
所以配之前的一个。不过这么写代码的也真是牛逼!