感觉 double 精度不够用啊

查看 140|回复 12
作者:tool2d   
这几天程序有一个 bug ,查出来是计算一个三角形面积,理论上应该是负数,但是函数算出来是正数,百思不得其解。
后来把计算面积公式里的 double 换成了 doubledouble 类,把精度加倍,结果就正确了。
寻思坐标也不是什么很大的值,怎么 double 就当场挂掉了呢?
=========
测试代码如下:
double buf[6];
buf[0*2+0] = 830776.16442871094; buf[0*2+1] = 430600.56744384766;
buf[1*2+0] = 830776.37707519531; buf[1*2+1] = 430600.68286132813;
buf[2*2+0] = 830776.16430664063; buf[2*2+1] = 430600.56732177734;
int numvertex = 3;
double area = 0.0;
for (int p=numvertex-1,q=0; q<numvertex; p=q++)
{
double a1 = buf[p*2+0] * buf[q*2+1];
double a2 = buf[q*2+0] * buf[p*2+1];
area += a1 - a2;
}
最终 area 结果
如果是 double ,那么值是 0.0000610 (错误)
如果是 doubledouble ,那么值是-0.0000118 (正确)
看起来是计算误差问题,但结果一个正,另一个负,足以把程序逻辑搞得天翻地覆。

buf, double, area, numvertex

liuidetmks   
可能你需要把工时修改下,尽量减少 值相近的数相减,做很小的数的除法
randomxb   
浮点数能表示的数在大值上是比较稀疏的, 分布在 0 附近的更集中.
你这两个 double 相乘结果更大了, 所以误差会更大也好解释.
你可以试试把大值规整变小再算下, 比如坐标平移到 0 附近, 结果会更准确.
tool2d
OP
  
@randomxb 我试了一下把坐标偏移到(0,0),对这个例子似乎可行。
但总觉得治标不治本,这种精度不够就和地雷差不多,随时会炸。
MicrosoftYK   
用高斯面积公式或海伦公式试试,同时可以把坐标值进行归一化,映射到一个较小的范围内,这样计算的时候可能会降低一些舍入误差
lakehylia   
如果你需要超高精度的浮点计算,推荐使用专门的超高精度的库。比如 java 里面的 BigDecimal 类。
lakehylia   
超高精度的库,内部实现,其实就是以字符来存储每一位十进制数位。然后自己实现一套加减乘除等算法。因为计算机的二进制是没办法精确表达十进制浮点数的。
tool2d
OP
  
@lakehylia 用高精度类是可以,我就是直觉上认为坐标不算极大数,也不算极小数,用 double 应该能搞定,没想到精度会渗出。
被 double 偷袭了一次,大意了。
MicrosoftYK   
同楼上,c/c++可以使用 GMP Library
cy18   
这东西不能看绝对精度,要看相对精度。
你这问题相对精度的量级是 0.0000610/(830776.16442871094*430600.56744384766),太高了。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部