7.2 生成表格

循环非常适合用于生成和显示表格型数据。计算机还未面世时,人们必须手工计算对数、正弦、余弦等常见的数学函数。为简化这种工作,有些书提供了表格,让你能够查找各种函数的值,但手工创建这样的表格既缓慢又繁琐,并且结果常常错误百出。

计算机面世后,大家最初的反应之一是:太好了,可用计算机来生成这样的表格了,并确保它们没有任何错误。事实证明确实如此,但人们的目光还是太短浅了,不久后,计算机就非常普及,这些打印出来的表格也就被淘汰了。

但对于有些运算来说,计算机依然要先在值表中查找近似结果,再通过计算来提高结果的精度。然而,有些值表存在错误,其中最著名的是最初的 Intel 奔腾处理器用来计算浮点数除法的值表(参见 https://en.wikipedia.org/wiki/Pentium_FDIV_bug)。

虽然“对数表”不再像以前那么有用了,但它依然是迭代的典范。下面的循环显示了一个表格,其中左边一列是一系列值,而右边一列是这些值的对数:

  1. int i = 1;
  2. while (i < 10) {
  3. double x = (double) i;
  4. System.out.println(x + " " + Math.log(x));
  5. i = i + 1;
  6. }

这个程序的输出如下:

  1. 1.0 0.0
  2. 2.0 0.6931471805599453
  3. 3.0 1.0986122886681098
  4. 4.0 1.3862943611198906
  5. 5.0 1.6094379124341003
  6. 6.0 1.791759469228055
  7. 7.0 1.9459101490553132
  8. 8.0 2.0794415416798357
  9. 9.0 2.1972245773362196

Math.log 计算自然对数,即以 e 为底的对数。在计算机应用领域常常需要计算以 2 为底的对数,为此可使用下面的公式:

\log_2x=\frac{\log_{{\rm e}}x}{\log_{{\rm e}}2}

我们可将前面的循环修改成下面这样:

  1. int i = 1;
  2. while (i < 10) {
  3. double x = (double) i;
  4. System.out.println(x + " " + Math.log(x) / Math.log(2));
  5. i = i + 1;
  6. }

结果如下:

  1. 1.0 0.0
  2. 2.0 1.0
  3. 3.0 1.5849625007211563
  4. 4.0 2.0
  5. 5.0 2.321928094887362
  6. 6.0 2.584962500721156
  7. 7.0 2.807354922057604
  8. 8.0 3.0
  9. 9.0 3.1699250014423126

我们在每次循环中都将 x 的值加 1,从而得到一个等差数列。如果不将 x 加 1,而是乘以一个常数,将得到一个等比数列:

  1. final double LOG2 = Math.log(2);
  2. int i = 1;
  3. while (i < 100) {
  4. double x = (double) i;
  5. System.out.println(x + " " + Math.log(x) / LOG2);
  6. i = i * 2;
  7. }

第 1 行将 Math.log(2) 存储在一个 final 变量中,以免反复计算这个表达式的值;最后一行将 x 乘以 2。结果如下:

  1. 1.0 0.0
  2. 2.0 1.0
  3. 4.0 2.0
  4. 8.0 3.0
  5. 16.0 4.0
  6. 32.0 5.0
  7. 64.0 6.0

这个表格列出了 2 的幂及其以 2 为底的对数。虽然对数表已毫无用处,但对计算机科学家来说,知道 2 的幂大有裨益!