Long Luo's Life Notes

每一天都是奇迹

By Long Luo

挖坑

假如你知道浮点数的话,你就知道为什么了!

按照 IEEE 754 浮点数标准 制定的 浮点数运算法则, float 类型的单精度浮点数 的尾数部分有 \(\large {23}\) 位二进制数,如下图所示:

IEEE 754 Single Floating Point Format

在十进制下,大致相当于 \(\large {\log_{10}{2^{23}} = 23 \cdot \log {2} \approx 23 \times 0.301 \approx 6.9}\) ,有效数字大约有 \(\large {7}\) 位。

所以当 \(\large {x = 1000001}\) 时,我们应该使用 double 类型的双精度浮点数 [^12] ,这样才能保证结果有足够的精度

双精度浮点数的尾数部分有 \(\large {52}\) 位,如下图所示:

IEEE 754 Double Floating Point Format

在十进制中大致相当于 \(\large {\log_{10}{2^{52}} = 52 \cdot \log {2} \approx 52 \times 0.301 \approx 15.6}\) ,也就是说当 \(\large {x}\) 有效数字是 \(\large {[7, 15]}\) 时,我们应该使用 double 类型的双精度浮点数可以保证精度!

但这仍然有个问题,那就是 \(\large {x}\) 有效数字 超过 \(\large {15}\) 位,应该怎么办?

参考文献

  1. IEEE 754
  2. Floating-point arithmetic
  3. Single-precision floating-point format
  4. Double-precision floating-point format

By Long Luo

之前写过一篇介绍 CORDIC 算法 1 的文章,里面提到 CORDIC 算法的 不足 之处,CORDIC 算法的输入角度范围需要在 \([−99.88^{\circ} , 99.88^{\circ}]\) ,那么我们不禁要问,如果输入角度 \(\large {\theta }\) 很大的话,怎么处理呢?

这个问题同样存在于 泰勒展开式(Taylor series) 2 中,比如 \(\large {\sin (x) }\)\(\large {\cos (x) }\) 的泰勒展开式:

\[ \sin(x) = x - \frac {1}{3!}x^3 + \frac {1}{5!}x^5 - \frac {1}{7!} x^7 + \frac {1}{9!} x^9 + o(x^9) \quad \forall x \subset \mathbb{R} \]

\[ \cos(x) = 1 - \frac {1}{2!}x^2 + \frac {1}{4!}x^4 - \frac {1}{6!} x^6 + \frac {1}{8!} x^8 + o(x^8) \quad \forall x \subset \mathbb{R} \]

虽然在整个实数集 \(\large { \mathbb{R}}\) 都成立,但是在实际应用中因为展开项数限制和浮点数的精度限制, \(\large {x}\) 的范围只有在接近 \(\large {0}\) 的时候才有比较高的精度。

但是实际应用中,如果输入 \(\large {x}\) 很大的话,比如 \(\large {2^{32}, 10^{10}, 10^{22} \dots }\) 情况下怎么得到足够精确的值呢?

中学里我们知道三角函数是周期函数,对于比较大的值,我们可以使用下面的公式将值归约到一个比较小的范围内。

\[ x' = x - 2k \pi \quad k \subset \mathbb{Z} \]

这就是我们今天要讲的 参数归约(Argument Reduction) 算法。

从小学计算题开始

参数归约 听起来就很唬人,什么是参数啊,什么归约啊,都是些高大上的名词,听起来云里雾里的!

为了不让大家产生厌倦和畏难心理,我们先从一道小学数学计算题开始:

不借助计算器,计算 \(\large {66600 \times 666000}\) 的值!

对于这道题,大家可能会列出下列算术:

\[ 66600 \times 666000 = 666 \times 666 \times 100000 = 44355600000 \]

但其实呢,我们也可以使用下面的方法:

\[ \begin{aligned} 66600 \times 666000 &= 111^2 \times 4 \times 9 \times 10^5 \\&= 444 \times 999 \times 10^5 \\&= 444 \times (1000 - 1) \times 10^5 \\&= 4443556 \times 10^5 \end{aligned} \]

如果我说上面这 \(\large {2}\) 种方法都用到了参数归约的思想,你可能会感到震惊,什么?这种小学计算题也用到了参数归约算法吗?

阅读全文 »
0%