双浮点精度

时间:2018-01-26 15:55:04

标签: c numerical-methods differential-equations numerical-analysis

我用Gauss-Seidel方法解决拉普拉斯方程,但在某些地区,它显示出类似高原的方面。形式上,即通过数值分析,即使梯度几乎为零,也不应存在这样的区域。

我不得不相信双精度不足以执行算术并且需要使用大量的库(从而破坏了性能,因为现在它将由软件完成)。或者,我应该以不同的顺序执行操作,旨在保留小数的一些重要性。

实施例

Cell(13,14,0)正在通过7点网格(在3D中)进行更新,其邻居是:

(12,14,0)=  0.9999999999999936; // (x-)
(14,14,0)=  0.9999999999999969; // (x+)
(13,13,0)=  0.9999999999999938; // (y-)
(13,15,0)=  1.0000000000000000; // (y+)
(13,14,-1)= 1.0000000000000000; // (z-)
(13,14,1)=  0.9999999999999959; // (z+)

因此,单元格(13,14,0)的新值将被评估为:

p_new = (0.9999999999999936 + 0.9999999999999969 + 0.9999999999999938 + 1.0000000000000000 + 1.0000000000000000 + 0.9999999999999959) / 6.0 ;

导致p_new为1.0000000000000000,应为0.9999999999999966。

代码

#include <stdio.h>

int main()
{
    double ad_neighboor[6] = {0.9999999999999936, 0.9999999999999969,
                              0.9999999999999938, 1.0000000000000000,
                              1.0000000000000000, 0.9999999999999959};

    double d_denom = 6.0;

    unsigned int i_xBackward=0;
    unsigned int i_xForward=1;

    unsigned int i_yBackward=2;
    unsigned int i_yForward=3;

    unsigned int i_zBackward=4;
    unsigned int i_zForward=5;

    double d_newPotential = (ad_neighboor[i_xForward] + ad_neighboor[i_xBackward] +
                             ad_neighboor[i_yForward] + ad_neighboor[i_yBackward] +
                             ad_neighboor[i_zForward] + ad_neighboor[i_zBackward] ) / d_denom;

    printf("%.16f\n", d_newPotential);
}

2 个答案:

答案 0 :(得分:2)

因为你正在解决:

d²(phi)/dx² + d²(phi)/dy² = 0

相反,你可以解决同等问题:

d²(phi')/dx² + d²(phi')/dy² = 0

其中,phi' = phi - 1

请记住以phi'

的形式应用边界条件

最后,在解决方案收敛后,您可以将解决方案设为phi = 1 + phi'

我假设边界值接近1。

我还没试过这个,但我认为数字会以浮点表示法的有效数字表示,因此截断误差会减少。

答案 1 :(得分:0)

您的粒度对于平台上的双精度浮点类型来说太精细了。

在大多数情况下,您可以通过调整粒度来解决此问题。如果你需要任何说服力,15个重要的粒度数字足以将太阳系与1厘米长的正方形的轨道或冥王星相连!对于这种方法,我倾向于保留至少四个数量级来消除数值噪声。

在极少数情况下,您应该考虑切换到另一种数据类型,例如long double(如果与您的平台不同double)或任意精度类型