最近学数值计算,第一次体会到浮点数精度的重要性了。
32 位机器上单精度浮点数有效数字只有 7 位。原因很简单,IEEE 754 (wiki 百科上的介绍很不错,不过访问受限,所以给了另外一个)的浮点数标准中 fraction 占 23 个 bit,换算到十进制的话就是 7 位。严格来说,对 normalized 形式的浮点数,因为小数点前的 1 被省略了, 所以其实是 24 个bit 也就是有 8 位有效数字,但是对于很小的正数,在 denormalized 的形式下,省略的那个 bit 是 0,对有效数字没有贡献,所以只有 7 位有效数字。
如果以单精度的浮点数来计算,要求得到误差小于 10-7 的结果,可以认为这个是不可能完成的任务吧。(我不知道有没有什么算法可以做到,有的话就太牛了。)输入数据的精度就只有 7 位有效数字,在计算过程中还要产生误差,要求最后的结果误差还要小于 10^(-7) 次方,听起来就比较愚蠢,但是我还是犯了这样的错误。
不过可以给自己一点借口。程序是用 Common Lisp 写的,刚开始使用,了解还不多,而 Common Lisp 默认使用的是单精度的浮点数。于是就发现我写的 Stiffenson 方法上千万次的迭代了还是迭代不到误差小于 10^(-7),更可笑的是根本就不收敛。千万次的 Stiffenson 方法迭代,算了好久得到这样的结果,瀑布汗啊…… 查程序半天没看出问题,最后才想到是浮点数精度的问题。改成双精度的,问题马上解决。
解决这种问题导致的错误真是痛苦……
数值计算的作业用 Lisp 这样的语言做真是非常棒,有理数精度基本上只受内存限制,函数当参数随便传,不像用 C 的话还得传指针,更何况还有高阶函数。另外边写边调试也很爽!