GSL2.7求解非线性方程组的多维根实例

最近项目中需要利用C/C++求解一个非线性方程组,经过调研,发现GSL库可以满足该要求。

先在win10下编译安装一下这个库:VS2019下编译与配置GSL2.7【Release x64版】

参考GSL2.7官方求多维根的教程:Multidimensional Root-Finding

也可以直接看我翻译的文章:通过GSL2.7解非线性方程组的多维根

本人将求解多维根的程序写成一个类GSLSLover,方便外部程序调用其方法GSLSLover::iterationSlover

待求解的非线性方程组如下:

{ x x 3 c o s α s i n β − x y 3 s i n α + x z 3 c o s α c o s β = z x 3 c o s β − z z 3 s i n β y x 3 c o s α s i n β − y y 3 s i n α + y z 3 c o s α c o s β = z x 3 s i n α s i n β + z y 3 c o s α + z z 3 s i n α c o s β \begin{cases} \begin{aligned} xx_3cos{\alpha}sin\beta-xy_3sin\alpha+xz_3cos{\alpha}cos\beta &= zx_3cos{\beta}-zz_3sin\beta\\ yx_3cos{\alpha}sin\beta-yy_3sin\alpha+yz_3cos{\alpha}cos\beta &= zx_3sin{\alpha}sin\beta+zy_3cos\alpha+zz_3sin{\alpha}cos\beta \end{aligned} \end{cases} { xx3cosαsinβxy3sinα+xz3cosαcosβyx3cosαsinβyy3sinα+yz3cosαcosβ=zx3cosβzz3sinβ=zx3sinαsinβ+zy3cosα+zz3sinαcosβ

其中,坐标 ( x , y , z ) (x,y,z) (x,y,z) ( x 3 , y 3 , z 3 ) (x_3,y_3,z_3) (x3,y3,z3)待传入参数,但是其值是确定的。该二元非线性方程组的待解量是: α \alpha α β \beta β

gsl.h

#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>

struct sparams  
{
    
    
	double x_1;
	double y_1;
	double z_1;
	double x_3;
	double y_3;
	double z_3;
};

class GSLSlover {
    
    
public:

	const gsl_multiroot_fsolver_type* T;
	gsl_multiroot_fsolver* s;
	int status;
	size_t i, iter = 0;
	const size_t n = 2;
	struct sparams p; // 待定
	double x_init[2] = {
    
     0, 0 };
	gsl_vector* x;
	gsl_multiroot_function f;


	GSLSlover();
	~GSLSlover();

	//static int camera_f(const gsl_vector* x, void* params, gsl_vector* f);
	void print_state(size_t iter, gsl_multiroot_fsolver* s);
	void iterationSlover(double x1, double y1, double z1, double x3, double y3, double z3);
};

gsl.cpp

#include "gsl.h"

int camera_f(const gsl_vector* x, void* params, gsl_vector* f)
{
    
    
	double a = ((struct sparams*)params)->x_1; // 第一帧的目标点坐标
	double b = ((struct sparams*)params)->y_1;
	double c = ((struct sparams*)params)->z_1;
	double x_3 = ((struct sparams*)params)->x_3; // 传进去的坐标
	double y_3 = ((struct sparams*)params)->y_3;
	double z_3 = ((struct sparams*)params)->z_3;
	const double alpha = gsl_vector_get(x, 0);
	const double beta = gsl_vector_get(x, 1);
	const double y0 = a * x_3 * cos(alpha) * sin(beta) - a * y_3 * sin(alpha) + a * z_3 *
		cos(alpha) * cos(beta) - c * x_3 * cos(beta) + c * z_3 * sin(beta);
	const double y1 = b * x_3 * cos(alpha) * sin(beta) - b * y_3 * sin(alpha) + b * z_3 *
		cos(alpha) * cos(beta) - c * x_3 * sin(alpha) * sin(beta) - c * y_3 * cos(alpha) - c * z_3 *
		sin(alpha) * cos(beta);
	gsl_vector_set(f, 0, y0);
	gsl_vector_set(f, 1, y1);
	return GSL_SUCCESS;
}


GSLSlover::GSLSlover()
{
    
    
	x = gsl_vector_alloc(n);

	gsl_vector_set(x, 0, x_init[0]);
	gsl_vector_set(x, 1, x_init[1]);

	T = gsl_multiroot_fsolver_hybrids;
	s = gsl_multiroot_fsolver_alloc(T, 2);
}

GSLSlover::~GSLSlover()
{
    
    
	gsl_multiroot_fsolver_free(s);
	gsl_vector_free(x);
}

void GSLSlover::print_state(size_t iter, gsl_multiroot_fsolver* s)
{
    
    
	printf("iter = %3u x = % .3f % .3f "
		"f(x) = % .3e % .3e\n",
		iter,
		gsl_vector_get(s->x, 0),
		gsl_vector_get(s->x, 1),
		gsl_vector_get(s->f, 0),
		gsl_vector_get(s->f, 1));
}

void GSLSlover::iterationSlover(double x1, double y1, double z1, double x3, double y3, double z3)
{
    
    
	p.x_1 = x1;
	p.y_1 = y1;
	p.z_1 = z1;
	p.x_3 = x3;
	p.y_3 = y3;
	p.z_3 = z3;
	f = {
    
     &camera_f, n, &p };
	gsl_multiroot_fsolver_set(s, &f, x);
	
	iter = 0; // 多次调用该方法时一定需要清零!
	do
	{
    
    
		iter++;
		status = gsl_multiroot_fsolver_iterate(s);
		//print_state(iter, s);
		if (status) /* check if solver is stuck */
			break;
		status =
			gsl_multiroot_test_residual(s->f, 1e-7);
	} while (status == GSL_CONTINUE && iter < 50);
	printf("status = %s\n", gsl_strerror(status));
}

在主程序main.cpp中测试代码如下

#include <stdlib.h>
#include <stdio.h>
#include "gsl.h"
#include <iostream>

using namespace std;

int main(void)
{
    
    
	GSLSlover gs;
	double x3 = 9.0;
	double y3 = 6.0;
	double z3 = 8.0;
	double x = 5.0;
	double y = 5.0;
	double z = 5.0;
	gs.iterationSlover(x, y, z, x3, y3, z3);

	cout << "alpha = " << gsl_vector_get(gs.s->x, 0) << endl;
	cout << "beta = " << gsl_vector_get(gs.s->x, 1) << endl;
	return 0;
}

输出结果

status = success
alpha = 0.207568
beta = 0.143063

编译生成时可能会遇到错误如下

错误	LNK2001	无法解析的外部符号    gsl_multiroot_fsolver_hybrids	

不用担心,去https://github.com/ampl/gsl找到缺失的.c文件并添加到工程下,即可运行程序。具体细节可参考文末给出的第二篇文章。

参考文献

  1. 有没有C/C++解非线性方程组的库?
  2. Windows配置GSL简明教程

猜你喜欢

转载自blog.csdn.net/Star_ID/article/details/125720569