gsl_poly.h
P(x)=c[0]+c[1]x+c[2]x2+⋯+c[len−1]xlen−1
1
2
3
4
5
6
7
8
9
10
11
12
|
// gsl_poly.h
/* real polynomial, real x */
INLINE_DECL double gsl_poly_eval(const double c[], const int len, const double x);
/* real polynomial, complex x */
INLINE_DECL gsl_complex gsl_poly_complex_eval(const double c [], const int len, const gsl_complex z);
/* complex polynomial, complex x */
INLINE_DECL gsl_complex gsl_complex_poly_complex_eval(const gsl_complex c [], const int len, const gsl_complex z);
/* 计算多项式以及多项式的多阶导数,多阶导数的计算结果存在 res 数组中,从第 0 阶开始 */
int gsl_poly_eval_derivs(const double c[], const size_t lenc, const double x, double res[], const size_t lenres);
|
-
差商如何计算?
给定 n+1 个数据点(插值点),(x0,y0),(x2,y2)⋯(xn,yn),那么就可以计算差商了 。
-
差商有什么用?
构建多项式
比如构建牛顿多项式,其利用差商可以表示为:
N(x)=y0+j=1∑n[y0,y1,⋯yj](x−x0)(x−x1)⋯(x−xj−1)
可以看到,利用差商 [y0,y1,⋯yj],插值点的 x 坐标,就可以构造出一个牛顿多项式。
也可以通过差商来构建厄密特多项式。
比如,对 n+1 个插值点 (x0,y0),(x2,y2)⋯(xn,yn),不仅插值多项式要过插值点,同时插值多项式也要满足一阶导数条件,利用差商,相应的厄密特多项式可以写为:
H2n+1(x)=y0+j=1∑2n+1[m0,m1,⋯,mj](x−z0)(x−z1)⋯(x−zj−1)
其中:m2j=m2j+1=yj,z2j=z2j+1=yj
总结一下:通过差商配合插值点的横坐标就可以构造出多项式了。其实就是多项式的差商表述形式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
// gsl_poly.h
/*
dd 差商数组,x 插值点横坐标数值,y 插值点横坐标数组,size 插值点数
根据 x, y 计算差商储存在 dd 中
*/
int
gsl_poly_dd_init(double dd[], const double x[], const double y[],
size_t size);
/*
根据 dd, xa 构造的多项式,计算在点 x 处的值
内联(ifdef HAVE_INLINE)
*/
INLINE_DECL double
gsl_poly_dd_eval(const double dd[], const double xa[], const size_t size, const double x);
/*
c 泰勒系数,xp 泰勒展开点,w 为工作空间,长度为 size
根据 dd, x 构造的多项式在点 xp 进行泰勒展开,泰勒系数存在 c 中
*/
int
gsl_poly_dd_taylor(double c[], double xp,
const double dd[], const double x[], size_t size,
double w[]);
/*
z 厄密特(一阶导条件)插值多项式的等效插值点横坐标数组,dd 厄密特差商数组
dya 一阶导条件,长度为 size
根据插值点 xa, ya, 一阶导条件 dya,计算厄密特多项式的差商和等效插值点横坐标,存储在 dd 和 z 中
*/
int
gsl_poly_dd_hermite_init(double dd[], double z[], const double xa[], const double ya[],
const double dya[], const size_t size);
|
ax2+bx+c=0
1
2
3
4
|
// gsl_poly.h
/*计算实根,无根时,x0,x1 不变,一个根 x0, 两个根 x0, x1 升序*/
int gsl_poly_solve_quadratic(double a, double b, double c,
double * x0, double * x1);
|
az2+bz+c=0
1
2
3
4
5
|
// gsl_poly.h
/*一个根 z0, 两个根 z0, z1 升序,先按实部,再按虚部*/
int
gsl_poly_complex_solve_quadratic(double a, double b, double c,
gsl_complex * z0, gsl_complex * z1);
|
1
2
3
4
5
6
7
8
|
// gsl_poly.h
int gsl_poly_solve_cubic(double a, double b, double c,
double * x0, double * x1, double * x2);
int
gsl_poly_complex_solve_cubic(double a, double b, double c,
gsl_complex * z0, gsl_complex * z1,
gsl_complex * z2);
|
使用迭代的方法寻根
gsl_poly_complex_workspace
定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// gsl_poly.h
typedef struct
{
size_t nc ;
double * matrix ;
}
gsl_poly_complex_workspace ;
// vcruntime.h
#ifdef _WIN64
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
typedef __int64 intptr_t;
#else
typedef unsigned int size_t;
typedef int ptrdiff_t;
typedef int intptr_t;
#endif
|
1
2
3
4
5
6
7
|
// gsl_poly.h
// n 多项式的系数个数
// 返回一个工作空间指针
gsl_poly_complex_workspace * gsl_poly_complex_workspace_alloc(size_t n);
// 清理工作空间,根据工作空间指针 w
void gsl_poly_complex_workspace_free(gsl_poly_complex_workspace * w);
|
P(x)=a0+a1x+a2x2+⋯+an−1xn−1
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// gsl_poly.h
/*
n 系数数组长度,最高阶系数要求非0
将 n-1 个复根,存在 z 中, z 为 double 指针,指向长度为 2n-2 的数组
如果找到根,返回 GSL_SUCCESS
*/
int
gsl_poly_complex_solve (const double * a, size_t n,
gsl_poly_complex_workspace * w,
gsl_complex_packed_ptr z);
// gsl_complex.h
typedef double * gsl_complex_packed_ptr ;
|
计算:P(x)=x5−1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#include <stdio.h>
#include <gsl/gsl_poly.h>
int
main(void)
{
int i;
/* coefficients of P(x) = -1 + x^5 */
double a[6] = { -1, 0, 0, 0, 0, 1 };
double z[10]; // 因为是复根,所以是 2x5=10
gsl_poly_complex_workspace* w
= gsl_poly_complex_workspace_alloc(6);
gsl_poly_complex_solve(a, 6, w, z);
gsl_poly_complex_workspace_free(w);
for (i = 0; i < 5; i++)
{
printf("z%d = %+.18f %+.18f i\n",
i, z[2 * i], z[2 * i + 1]);
}
return 0;
}
|
https://www.gnu.org/software/gsl/doc/html/poly.html