Q5
同作业1. Q5.
Q9
建议对前缀++和后缀++仍有疑虑的同学阅读这篇博文:[Java] i++与++i的区别(后缀++与前缀++)
int m = 3, n = 5, k = 0;
while ((m++) < (--n))
++ k;
第一次执行m++ < --n
m++
- m=4, 返回m的旧值3.
--n
- n=4, 返回n的新值4.
3 < 4 成立,++ k, k变成1.
第二次执行m++ < --n
m++
- m=5, 返回4
--n
- n=3, 返回3
4 < 3 不成立,循环结束。
Q11
-- i --; // 这里语法错误,题目不对
Q12
根据语法,case后面需要跟break, 才会跳出switch语句,否则将依次执行正确case后面的所有语句。所以此题的运行结果是:
int i = 10, j = 18, k = 30;
switch(j - i) {
case 8:
k ++; // k = 31
case 9:
k += 2; // k = 33
case 10:
k += 3; // k = 36
default:
k /= j; // k = 2
}
Q13
for (int i = 0, j = 1; j < 5; j += 3)
i = i + j;
初始化:
- i = 0
- j = 1
第一次迭代:
- j < 1成立,开始执行
- i = i + j = 1
- j = j + 3 = 4
第二次迭代:
- j < 5成立,开始执行
- i = i + j = ?
- j = ?
第三次迭代:
- ...
注意到,j < 5不成立,将中止循环,此时i的值即为结果。
Q32
boolean even = false;
if (even = true)
System.out.println("It is even!");
根据
Java Language Specification -- 15.1 Evaluation, Denotation, and Result, 一个表达式的返回值可能是:
- A variable(一个变量)
- 假如a是一个变量的名字,那么表达式a(单个变量名就可以作为一个表达式), 可以认为它返回的是变量a
- A value(一个值)
- 比如说表达式5, 可以认为它返回的值是5.
- Nothing (the expression is said to be void, 我们称这个表达式是void)
对于赋值表达式(assignment expression, 亦即"="操作符),以v = a为例,它会做两件事:
1. 将a的值赋值给变量v
2. 返回v的值
所以对于 if (even = true), 这里发生了三件事:
1. 将true赋值给even
2. 将even的值(亦即true)返回
3. if接收到这个返回值true,认为条件成立,执行分支内的语句(亦即println)
Q33, Q34 同 Q32
Q71
0.
解决这题的关键,是理解floating-point是有误差的,无法被精确表示的。
1. 什么是floating-point(浮点数)
如wikipedia -- Floating point所示,这里的floating point指的是浮点数,非正式地可以理解成“小数”.
在Java中,无论是float还是double类型,它们都是浮点,区别是在于:
- float是32位的单精度(type: single, wikipedia上有写)
- double是64位的双精度浮点(type: double, wikipedia上有写)
所以题目中所说的floating-point指的不是特定的某种类型(float or double), 指的是浮点数。
2. 为什么浮点数无法被精确表示
2.1 浮点的二进制表示
因为计算机采用了同一种特殊的方式,用来表示浮点数。
直观的,我们考虑 六又八分之五(6.625, 这个网站不能写数学公式...)这个分数。它的二进制表示是
110.101 (左边是6,小数点右边是5(代表5/8))
进一步,它可以写成
0.110101 * (2^3)
所以那么在机器中,如果我们用32位来表示它,那么它的二进制表示是:
0 1000_0001 1010_1000_0000_0000_0000_000
1) 第一个0, 代表这是一个正数
2) 中间8个bit, 我们管它叫significan, 十进制表示是129
3) 最后23个bit, 叫做precision
我们可以用这三段数字翻译出6.625:
+ 1.precision * 2^(significan - 127)
也就是 + 1.10101 * 2 ^ (129 - 127) = 110.101, 也就是6.625.
感兴趣但仍不理解的同学,可以去群里下载我上传的《Introduction to Computing Systems》,原书39页 Chapter 2.7 Other Representation 中有讲到这个6.625的例子。OS: 作者Yale Patt几乎每年暑假都有来浙大讲课,讲得通俗易懂,据说他有时会跟高中生讲这门课。即使你不是CS专业也可以旁听或选课(要花费一些精力)。大三时,学院有邀我去当他的助教,我当时还在温哥华就没回来:D
2.2 这样表示的优点 -- 能表示一定范围内的小数
用32位就可以表示大概是[2^-126, 2^127]的小数了,而且这个范围比32位int所表示的大概是[-2^31, 2^31]的范围大得多。
2.3 这样表示的缺点 -- 精度不够
在2.1中,6.625刚好可以用110.101来表示六又八分之五。但大家考虑0.1就会发现,它是无法被精确表示的,这个表示法,只能利用23位的precision尽量得去近似这个小数。
所以浮点用等于号来比较,经常是不能获得数学中相等的情况的——因为这两个数的32位二进制可能在有效数字最后几位有所差异。
3. 一个例子
public class DoubleTest {
public static void main(String[] args) {
for (double d = 0; d < 1.0; d += 0.1)
// 每次打印d的值
System.out.println(d);
}
}
打印结果:
大家可以发现,d每次增加0.1, 但是有些时候在最后几位还是会出现非零的情况的。
所以结论就是一开始和大家说的“0. floating-point是有误差的,是无法被精确表示的”.