我的目标是计算C编程语言中电子距离氢原子核的距离的概率分布函数(PDF)的数值积分。我已经编写了一个示例代码,但是由于我不能像我认为的那样增加限制,因此无法正确找到数值。我也包括了库,但我不能使用以下帖子中所述的值作为整体边界:min and max value of data type in C。在这种情况下,补救措施是什么?应该切换到另一种编程语言吗?任何帮助和建议都表示赞赏,提前谢谢。
编辑:经过一些值后,我得到错误分段错误。我用Wolframalpha检查了积分的实际结果为0.0372193。除此之外,如果我以较小的量增加k,我得到零,这就是我定义r [k] = k的原因,我知道它应该更小以提高精度。
#include <stdio.h>
#include <math.h>
#include <limits.h>
#define a0 0.53
int N = 200000;
// This value of N is the highest possible number in long double
// data format. Change its value to adjust the precision of integration
// and computation time.
// The discrete integral may be defined as follows:
long double trapezoid(long double x[], long double f[]) {
int i;
long double dx = x[1]-x[0];
long double sum = 0.5*(f[0]+f[N]);
for (i = 1; i < N; i++)
sum+=f[i];
return sum*dx;
}
main() {
long double P[N], r[N], a;
// Declare and initialize the loop variable
int k = 0;
for (k = 0; k < N; k++)
{
r[k] = k ;
P[k] = r[k] * r[k] * exp( -2*r[k] / a0);
//printf("%.20Lf \n", r[k]);
//printf("%.20Lf \n", P[k]);
}
a = trapezoid(r, P);
printf("%.20Lf \n", a);
}
最后一个代码:
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define a0 0.53
#define N LLONG_MAX
// This value of N is the highest possible number in long double
// data format. Change its value to adjust the precision of integration
// and computation time.
// The discrete integral may be defined as follows:
long double trapezoid(long double x[],long double f[]) {
int i;
long double dx = x[1]-x[0];
long double sum = 0.5*(f[0]+f[N]);
for (i = 1; i < N; i++)
sum+=f[i];
return sum*dx;
}
main() {
printf("%Ld", LLONG_MAX);
long double * P = malloc(N * sizeof(long double));
long double * r = malloc(N * sizeof(long double));
// Declare and initialize the loop variable
int k = 0;
long double integral;
for (k = 1; k < N; k++)
{
P[k] = r[k] * r[k] * expl( -2*r[k] / a0);
}
integral = trapezoid(r, P);
printf("%Lf", integral);
}
编辑最后一段代码:
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define a0 0.53
#define N LONG_MAX/100
// This value of N is the highest possible number in long double
// data format. Change its value to adjust the precision of integration
// and computation time.
// The discrete integral may be defined as follows:
long double trapezoid(long double x[],long double f[]) {
int i;
long double dx = x[1]-x[0];
long double sum = 0.5*(f[0]+f[N]);
for (i = 1; i < N; i++)
sum+=f[i];
return sum*dx;
}
main() {
printf("%Ld \n", LLONG_MAX);
long double * P = malloc(N * sizeof(long double));
long double * r = malloc(N * sizeof(long double));
// Declare and initialize the loop variable
int k = 0;
long double integral;
for (k = 1; k < N; k++)
{
r[k] = k / 100000.0;
P[k] = r[k] * r[k] * expl( -2*r[k] / a0);
}
integral = trapezoid(r, P);
printf("%.15Lf \n", integral);
free((void *)P);
free((void *)r);
}
特别是我已经通过在除法运算中使用浮点数来改变r [k]的定义,结果得到一个long double,而且正如我在上一篇评论中所说的那样,我不能使用大于Ns的Ns。 LONG_MAX / 100,我想我应该进一步调查代码和malloc以解决问题。我已经找到了通过限制分析获得的确切值;我已经用TI-89 Titanium和Wolframalpha(数字和分析)确认了结果,而不是自己做。当间隔尺寸减小时,梯形规则很好。非常感谢这里的所有海报,感谢他们的想法。值为2147483647 LONG_MAX并不像我预期的那样特别大,如果限制不是大约10到功率308?
答案 0 :(得分:6)
通常的梯形方法不适用于不正确的积分。因此,高斯求积法则要好得多,因为它们不仅提供2n-1的精确性(即,对于2n-1次多项式它们将返回正确的解),而且还通过使用正确的权重函数来管理不正确的积分
如果你的积分在双方都不合适,你应该试试Gauss-Hermite quadrature,否则请使用Gauss-Laguerre quadrature。
long double P[N], r[N], a;
P
的大小约为3MB,r
也是如此。这是太多的记忆。改为分配内存:
long double * P = malloc(N * sizeof(long double));
long double * r = malloc(N * sizeof(long double));
如果您不再需要<stdlib.h>
和free
,请不要忘记P
并使用r
。此外,您可能无法访问第N个条目,因此f[N]
错误。
现在Gauss-Laguerre使用exp(-x)
作为权重函数。如果您不熟悉高斯求积法:E(f)
的结果是w * f
的积分,其中w
是权重函数。
您的f
看起来像这样,并且:
f x = x^2 * exp (-2 * x / a)
等一下。 f
已包含exp(-term)
,因此我们可以用t = x * a /2
替换x并获取
f' x = (t * a/2)^2 * exp(-t) * a/2
由于exp(-t)
已经是我们的权重函数的一部分,因此您的函数现在完全符合Gauss-Laguerre积分。结果代码是
#include <stdio.h>
#include <math.h>
/* x[] and a[] taken from
* https://de.wikipedia.org/wiki/Gau%C3%9F-Quadratur#Gau.C3.9F-Laguerre-Integration
* Calculating them by hand is a little bit cumbersome
*/
const int gauss_rule_length = 3;
const double gauss_x[] = {0.415774556783, 2.29428036028, 6.28994508294};
const double gauss_a[] = {0.711093009929, 0.278517733569, 0.0103892565016};
double f(double x){
return x *.53/2 * x *.53/2 * .53/2;
}
int main(){
int i;
double sum = 0;
for(i = 0; i < gauss_rule_length; ++i){
sum += gauss_a[i] * f(gauss_x[i]);
}
printf("%.10lf\n",sum); /* 0.0372192500 */
return 0;
}