浮点数
By Long Luo
挖坑
假如你知道浮点数的话,你就知道为什么了!
按照 IEEE 754 浮点数标准 制定的 浮点数运算法则, float 类型的单精度浮点数 的尾数部分有 \(\large {23}\) 位二进制数,如下图所示:
在十进制下,大致相当于 \(\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}\) 位,如下图所示:
在十进制中大致相当于 \(\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}\) 位,应该怎么办?
参考文献
参数归约算法(Argument Range Reduction):如何在浮点数环境下计算超大数字的三角函数值?
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}\) 种方法都用到了参数归约的思想,你可能会感到震惊,什么?这种小学计算题也用到了参数归约算法吗?