7.9 练习

本章的示例代码位于仓库 ThinkJavaCode 的目录 ch07 中,有关如何下载这个仓库,请参阅前言中的“使用示例代码”一节。做以下的练习前,建议你先编译并运行本章的示例。

如果你还没有阅读 A.5 节,那么现在正是阅读的好时机。该节介绍了 Checkstyle——一款分析源代码众多方面的工具。

练习7-1

请看下面的方法,并思考问题:

  1. public static void main(String[] args) {
  2. loop(10);
  3. }
  4. public static void loop(int n) {
  5. int i = n;
  6. while (i > 1) {
  7. System.out.println(i);
  8. if (i % 2 == 0) {
  9. i = i / 2;
  10. } else {
  11. i = i + 1;
  12. }
  13. }
  14. }

(1) 绘制一个表格,用来显示变量 in 在循环期间的值。在这个表格中,每次迭代要占据一行,每列对应一个变量。

(2) 这个程序的输出是什么?

(3) 只要 n 的值为正,这个循环就终将结束。你能证明这一点吗?

练习7-2

给定数字 a,要求你计算它的平方根。一种解决方案是先粗略地猜测结果 x0,再用下面的公式提高结果的精度:

x_1=(x_0+a/x_0)/2

例如,要计算 9 的平方根,可从 x0=6 开始,再用前面的公式计算 x1=(6+9/6)/2 = 3.75,这更接近于准确的结果。我们可重复这个过程,根据 x1 计算 x2,再依次类推。就此例而言,x2=3.075,x3=3.00091。这种计算的速度非常快,很快就能找到正确的答案。

请编写一个名为 squareRoot 的方法,让它接受一个 double 值,并用前面的技巧计算其平方根的近似值。可不能用 Math.sqrt 哟!

为计算初始结果,可使用公式 a/2。这个方法应该不断迭代,直到两个相邻近似结果的差小于 0.0001。可用 Math.abs 计算差的绝对值。

练习7-3

在练习 6-9 中,你编写了一个以迭代方式计算幂的方法,它接受 doublex 和整数值 n,并返回 xn。现在请编写一个迭代方法来执行这种计算。

练习7-4

6.7 节中介绍了一个计算阶乘的递归方法,请编写方法 factorial 的迭代版本。

练习7-5

要想计算 ex 的值,一种办法是使用如下的无穷级数展开:

{\rm e}^x=1+x+x^2/2!+x^3/3!+x^4/4!\cdots

在上述级数中,第 i 项为“xi/i !”。

(1) 编写一个名为 myexp 的方法,它接受形参 xn,并将上述级数的前 n 项相加来计算 ex 的近似值。为计算阶乘,可使用 6.7 节中的方法 factorial,也可使用前一个练习中编写的迭代版本。

(2) 在上述级数中,每一项的分子都是前一项的分子乘以 x,而每一项的分母都是前一项的分母乘以 i。利用这一点可避免使用方法 Math.powfactorial,从而提高这个方法的效率。请按这种方式修改你在第 1 步编写的方法,并确定得到的结果相同。

(3) 编写一个名为 check 的方法,它接受形参 x,并显示 xmyexp(x)Math.exp(x) 的值,其输出类似于下面这样:

  1. 1.0 2.708333333333333 2.718281828459045

要想用制表符分隔各列的值,可使用转义序列 "\t"

(4) 修改级数包含的项数(checkmyexp 传递的第二个实参),并查看这种修改对结果准确度的影响。在 x 为 1 的情况下调整值,直到估算值与正确的结果相同为止。

(5) 在方法 main 中编写一个循环,依次用实参值 0.1、1.0、10.0 和 100.0 调用 check。随着 x 值不断变化,结果的准确度将如何变化?比较估算值和实际值有多少位相同。

(6) 在方法 main 中编写一个循环,依次用实参值 - 0.1、- 1.0、- 10.0 和 - 100.0 调用 check,看看准确度将如何变化。

练习7-6

要想计算 exp(-x2) 的值,一种办法是用如下的无穷级数展开:

\exp(-x^2)=1-x^2+x^4/2-x^66+\dots

在上述级数中,第 i 项为“(-1)ix2i/i !”。请编写一个名为 gauss 的方法,它接受形参 xn,并返回上述级数中前 n 项的和。编写这个方法时,可不能使用方法 factorialpow 哟!