我用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);
}
答案 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
)或任意精度类型