C 双浮点精度

C 双浮点精度,c,numerical-methods,differential-equations,numerical-analysis,C,Numerical Methods,Differential Equations,Numerical Analysis,我用高斯-赛德尔方法解拉普拉斯方程,但在某些地区,它表现出一种高原状的特征。形式上,即通过数值分析,即使梯度几乎为零,也不应存在此类区域 我不得不相信,双精度不足以执行算术,需要使用大量的库(破坏性能,因为现在它将由软件完成)。或者,我应该以不同的顺序进行运算,目的是保留小数的某些意义 例子 单元(13、14、0)正在由7点网格(在3D中)更新,其相邻区域为: (12,14,0)= 0.9999999999999936; // (x-) (14,14,0)= 0.99999999999999

我用高斯-赛德尔方法解拉普拉斯方程,但在某些地区,它表现出一种高原状的特征。形式上,即通过数值分析,即使梯度几乎为零,也不应存在此类区域

我不得不相信,双精度不足以执行算术,需要使用大量的库(破坏性能,因为现在它将由软件完成)。或者,我应该以不同的顺序进行运算,目的是保留小数的某些意义

例子 单元(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.999999999666

代码
#包括
int main()
{
双ad_邻域[6]={0.9999999936,0.9999999999969,
0.9999999999999938, 1.0000000000000000,
1.0000000000000000, 0.9999999999999959};
双d_denom=6.0;
无符号整数i_xBackward=0;
无符号整数i_xForward=1;
无符号整数i_yBackward=2;
无符号整数i_yForward=3;
无符号整数i_zBackward=4;
无符号整数i_zForward=5;
双d_新势=(ad_neighbor[i_xForward]+ad_neighbor[i_xBackward]+
与邻居[我向前]+与邻居[我向后]+
反邻居[我向前]+反邻居[我向后]/d\n;
printf(“%.16f\n”,d_新电位);
}

对于平台上的双精度浮点类型,您的粒度太细

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


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

对于平台上的双精度浮点类型,您的粒度太细

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

只有在极少数情况下,您才应该考虑切换到另一种数据类型,例如
长双精度
(如果您的平台不同于
双精度
),或任意精度类型。

因为您正在解算:

d²(φ)/dx²+d²(φ)/dy²=0
相反,您可以解决等效问题:

d²(φ')/dx²+d²(φ')/dy²=0
其中,
phi'=phi-1

记住根据
phi'
应用边界条件

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

这里我假设边界值接近于1

我没有尝试过这种方法,但我认为数字将以浮点表示法的有效数字表示,因此截断错误将减少。

因为您正在解决:

d²(φ)/dx²+d²(φ)/dy²=0
相反,您可以解决等效问题:

d²(φ')/dx²+d²(φ')/dy²=0
其中,
phi'=phi-1

记住根据
phi'
应用边界条件

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

这里我假设边界值接近于1


我没有尝试过,但我认为数字将以浮点符号的有效数字表示,因此,截断错误将减少。

可能会有所帮助。向我们展示您的代码,我们可能会告诉您如何改进它。无法复制:我从
printf(%.16f\n,p\u new)获取
p\u new
as
0.9999999966
from
printf(%.16f\n,p\u new)顺便说一句,您不需要行连续字符。与震级相比,差异非常小,导致显著性损失。重新排列公式,使小数字可以通过以下方式显示:
double adjustment=ad_neighbor[i_xForward];d_新势=((ad_neightor[i_xForward]-调整)+(ad_neightor[i_xBackward]-调整)+(ad_neightor[i_yForward]-调整)+(ad_neightor[i_yForward]-调整)+(ad_neightor[i_zForward]-调整)+(ad_neightor[i_zBackward]-调整))/d_denom)+调整最好更改坐标系,使所有坐标接近零。可能会有所帮助。向我们展示您的代码,我们可能会告诉您如何改进它。无法复制:我从
printf(%.16f\n,p\u new)获得
p\u new
0.9999999999966
顺便说一句,您不需要行连续字符。与震级相比,差异非常小,导致显著性损失。重新排列公式,使小数字可以通过以下方式显示:
double adjustment=ad_neighbor[i_xForward];d_新势=((ad_neightor[i_xForward]-调整)+(ad_neightor[i_xBackward]-调整)+(ad_neightor[i_yForward]-调整)+(ad_neightor[i_yForward]-调整)+(ad_neightor[i_zForward]-调整)+(ad_neightor[i_zBackward]-调整))/d_denom)+调整最好是改变坐标系,这样所有的坐标都接近零。我不是scal
#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);
}