使用C++库GNU Scientific Library求解非线性方程(组)

基础条件:Windows系统,clion,msvc C++工具链,GNU Scientific Library

到GSL官网https://www.gnu.org/software/gsl/ 下载 源代码文件,解压到硬盘中,我的路径为 G:\software\gsl28。先建立一个config.h文件放到G:\software\gsl28下面,内容为

cpp 复制代码
/* config.h manually created for MSVC on Windows */

/* 启用内联函数支持 */


#define HAVE_INLINE 1
#ifdef _MSC_VER
#define inline __inline
#endif

/* 标准头文件存在 */
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_STDINT_H 1
#define HAVE_INTTYPES_H 1
#define HAVE_SYS_TYPES_H 1

/* 标准库函数存在 */
#define HAVE_MEMCPY 1
#define HAVE_MEMMOVE 1
#define HAVE_STRDUP 1
#define HAVE_STRTOL 1
#define HAVE_STRTOUL 1
#define HAVE_VPRINTF 1

/* 数学函数声明存在(MSVC 提供这些函数) */
#define HAVE_DECL_HYPOT 1
#define HAVE_DECL_LOG1P 1
#define HAVE_DECL_EXPM1 1
#define HAVE_DECL_ACOSH 1
#define HAVE_DECL_ASINH 1
#define HAVE_DECL_ATANH 1
#define HAVE_DECL_LDEXP 1
#define HAVE_DECL_FREXP 1
#define HAVE_DECL_ISINF 1
#define HAVE_DECL_ISFINITE 1
#define HAVE_DECL_FINITE 1
#define HAVE_DECL_ISNAN 1

/* 选择 IEEE 接口(x86 架构) */
#define HAVE_GNUX86_IEEE_INTERFACE 1

/* C89 标准头文件都可用 */
#define STDC_HEADERS 1

/* 包信息 */
#define PACKAGE "gsl"
#define VERSION "2.7"
#define PACKAGE_BUGREPORT ""

/* stdlib.h 中有 EXIT_SUCCESS/EXIT_FAILURE */
#define HAVE_EXIT_SUCCESS_AND_FAILURE 1

/* 启用 SSE 扩展(x86 处理器) */
#define HAVE_FPU_X86_SSE 1

/* 无扩展精度寄存器(MSVC 不适用) */
/* #undef HAVE_EXTENDED_PRECISION_REGISTERS */

/* 定义 GSL_COERCE_DBL */
#ifdef HAVE_EXTENDED_PRECISION_REGISTERS
#define GSL_COERCE_DBL(x) (gsl_coerce_double(x))
#else
#define GSL_COERCE_DBL(x) (x)
#endif

/* 忽略丢弃指针的警告 */
#define DISCARD_POINTER(p) /* ignoring discarded pointer */

/* 默认启用范围检查(可以注释掉以关闭) */
/* #define GSL_RANGE_CHECK 0 */

/* 空指针检查 */
#define RETURN_IF_NULL(x) if (!x) { return ; }

#ifndef GSL_VAR
#define GSL_VAR extern
#endif

CMakeLists.txt内容如下:

cpp 复制代码
cmake_minimum_required(VERSION 3.30)
project(GSLnonlinearequations)

# 启用 C 语言支持
enable_language(C)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)  # 为 C 代码设置 C99 标准

set(GSL_ROOT "G:/software/gsl28")
#收集所有源文件(递归所有子目录,但排除测试文件)
file(GLOB_RECURSE GSL_SOURCES
        "${GSL_ROOT}/sys/*.c"
        "${GSL_ROOT}/err/*.c"
        "${GSL_ROOT}/cblas/*.c"
        "${GSL_ROOT}/blas/*.c"
        "${GSL_ROOT}/vector/*.c"
        "${GSL_ROOT}/matrix/*.c"
        "${GSL_ROOT}/permutation/*.c"
        "${GSL_ROOT}/complex/*.c"
        "${GSL_ROOT}/block/*.c"
        "${GSL_ROOT}/linalg/*.c"
        "${GSL_ROOT}/multiroots/*.c"
        "${GSL_ROOT}/min/*.c"
        "${GSL_ROOT}/poly/*.c"
        "${GSL_ROOT}/fit/*.c"
        "${GSL_ROOT}/statistics/*.c"
        "${GSL_ROOT}/rng/*.c"
        "${GSL_ROOT}/randist/*.c"
       # "${GSL_ROOT}/ieee-utils/*.c"
        "${GSL_ROOT}/test/*.c"
        "${GSL_ROOT}/roots/*.c"
        # 这里自己添加你需要的源文件
)

# 排除测试文件(通常包含 test 或 -test 的文件)
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/test.*\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/tests.*\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/bench.*\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/.*_source\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/apply_givens\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/cholesky_common\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/svdstep\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/dogleg\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/enorm\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/poly/balance\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/poly/companion\\.c$")
list(FILTER GSL_SOURCES EXCLUDE REGEX ".*/poly/qr\\.c$")

# 首先在构建目录中创建 gsl 文件夹
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gsl")

# 查找所有模块下的 gsl_*.h 头文件
file(GLOB_RECURSE GSL_HEADERS "${GSL_ROOT}/*/gsl*.h"  "${GSL_ROOT}/gsl*.h"  )

# 将每个头文件复制到构建目录的 gsl/ 下
foreach(header ${GSL_HEADERS})
    get_filename_component(name ${header} NAME)
    configure_file(${header} "${CMAKE_CURRENT_BINARY_DIR}/gsl/${name}" COPYONLY)
endforeach()


#  创建 GSL 静态库
# -------------------------------------------------------------------
add_library(gsl_static STATIC ${GSL_SOURCES})
# 设置包含路径:
#   - 构建目录下的 gsl/(用于外部包含 #include <gsl/...>)
#   - 源码根目录(因为库内部可能会引用其他模块的头文件,如 #include <gsl_vector.h>)
target_include_directories(gsl_static PUBLIC
        "${CMAKE_CURRENT_BINARY_DIR}"
        "${GSL_ROOT}"
)
# 对于 MSVC,关闭一些安全警告
if(MSVC)
    target_compile_definitions(gsl_static PRIVATE _CRT_SECURE_NO_WARNINGS  HAVE_CONFIG_H)
    # 告诉 MSVC 将文件作为 C 代码编译(避免 C++ 名称修饰)
    set_target_properties(gsl_static PROPERTIES LINKER_LANGUAGE C)
endif()



add_executable(GSLnonlinearequations main.cpp)
target_link_libraries(GSLnonlinearequations gsl_static)
# 同样为主程序添加包含路径(以便 #include <gsl/gsl_vector.h> 能找到)
target_include_directories(GSLnonlinearequations PRIVATE
        "${CMAKE_CURRENT_BINARY_DIR}"
)

main.cpp文件内容如下:

cpp 复制代码
#include <stdio.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
#include <gsl/gsl_roots.h>

// -------------------- 辅助函数:封装一维求根(Brent 方法)--------------------
double root_brent(gsl_function F, double lo, double hi, double epsrel) {
    const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
    gsl_root_fsolver *s = gsl_root_fsolver_alloc(T);
    gsl_root_fsolver_set(s, &F, lo, hi);

    int status;
    size_t iter = 0;
    double root;
    do {
        iter++;
        gsl_root_fsolver_iterate(s);
        root = gsl_root_fsolver_root(s);
        lo = gsl_root_fsolver_x_lower(s);
        hi = gsl_root_fsolver_x_upper(s);
        status = gsl_root_test_interval(lo, hi, 0, epsrel);
    } while (status == GSL_CONTINUE && iter < 1000);

    printf("迭代次数 = %zu, 状态 = %s\n", iter, gsl_strerror(status));
    gsl_root_fsolver_free(s);
    return root;
}

// -------------------- 辅助函数:封装通用多维方程组求解(Hybrids 方法)--------------------
void multiroot_hybrids(gsl_multiroot_function F, gsl_vector *x, double epsabs) {
    const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids;
    gsl_multiroot_fsolver *s = gsl_multiroot_fsolver_alloc(T, F.n);
    gsl_multiroot_fsolver_set(s, &F, x);

    int status;
    size_t iter = 0;
    do {
        iter++;
        status = gsl_multiroot_fsolver_iterate(s);
        if (status) break;
        status = gsl_multiroot_test_residual(s->f, epsabs);
    } while (status == GSL_CONTINUE && iter < 1000);

    printf("迭代次数 = %zu, 状态 = %s\n", iter, gsl_strerror(status));

    // 打印所有未知数的解
    printf("解: ");
    for (size_t i = 0; i < F.n; ++i) {
        printf("x%zu = %.8f  ", i, gsl_vector_get(s->x, i));
    }
    printf("\n");

    // 打印所有残差
    printf("残差: ");
    for (size_t i = 0; i < F.n; ++i) {
        printf("f%zu = %.2e  ", i, gsl_vector_get(s->f, i));
    }
    printf("\n");

    gsl_multiroot_fsolver_free(s);
}

// -------------------- 问题定义 --------------------
//一元方程 x^2 - 5 = 0
double square_minus_five(double x, void *params) {
    return x * x - 5.0;
}

// 一元方程 cos(x) = x
double cos_minus_x(double x, void *params) {
    (void)params;          // 未使用参数
    return cos(x) - x;
}

// Rosenbrock 方程组:  a(1-x0)=0, b(x1-x0^2)=0
struct rparams { double a, b; };
int rosenbrock_f(const gsl_vector *x, void *params, gsl_vector *f) {
    double a = ((struct rparams *)params)->a;
    double b = ((struct rparams *)params)->b;
    double x0 = gsl_vector_get(x, 0);
    double x1 = gsl_vector_get(x, 1);
    gsl_vector_set(f, 0, a * (1 - x0));
    gsl_vector_set(f, 1, b * (x1 - x0 * x0));
    return GSL_SUCCESS;
}

// 二元 Powell 病态方程组: 10000x1x2-1=0, e^(-x1)+e^(-x2)-1.0001=0
struct powell_params { double dummy; };
int powell_f(const gsl_vector *x, void *params, gsl_vector *f) {
    double x0 = gsl_vector_get(x, 0);
    double x1 = gsl_vector_get(x, 1);
    gsl_vector_set(f, 0, 10000.0 * x0 * x1 - 1.0);
    gsl_vector_set(f, 1, exp(-x0) + exp(-x1) - 1.0001);
    return GSL_SUCCESS;
}

// 三元 Helical 方程组(螺旋谷函数):
int helical_f(const gsl_vector *x, void *params, gsl_vector *f) {
    double x0 = gsl_vector_get(x, 0);
    double x1 = gsl_vector_get(x, 1);
    double x2 = gsl_vector_get(x, 2);

    double theta;
    if (x0 > 0)
        theta = atan(x1 / x0) / (2 * M_PI);
    else if (x0 < 0)
        theta = 0.5 + atan(x1 / x0) / (2 * M_PI);
    else
        theta = (x1 > 0) ? 0.25 : -0.25;

    gsl_vector_set(f, 0, 10.0 * (x2 - 10.0 * theta));
    gsl_vector_set(f, 1, 10.0 * (sqrt(x0 * x0 + x1 * x1) - 1.0));
    gsl_vector_set(f, 2, x2);
    return GSL_SUCCESS;
}

// 四元 Powell 奇异方程组
int powellsing_f(const gsl_vector *x, void *params, gsl_vector *f) {
    double x0 = gsl_vector_get(x, 0);
    double x1 = gsl_vector_get(x, 1);
    double x2 = gsl_vector_get(x, 2);
    double x3 = gsl_vector_get(x, 3);

    gsl_vector_set(f, 0, x0 + 10.0 * x1);
    gsl_vector_set(f, 1, sqrt(5.0) * (x2 - x3));
    gsl_vector_set(f, 2, pow(x1 - 2.0 * x2, 2.0));
    gsl_vector_set(f, 3, sqrt(10.0) * pow(x0 - x3, 2.0));
    return GSL_SUCCESS;
}


// -------------------- 主函数--------------------
int main() {
    // 1. 求解一元方程 x^2 - 5 = 0
    gsl_function F1 = {square_minus_five, NULL};
    double root1 = root_brent(F1, 0.0, 5.0, 1e-7);
    printf("一元方程 x^2-5=0 的解: x = %.8f\n\n", root1);

    // 2. 求解一元方程 cos(x) = x
    gsl_function F2 = {cos_minus_x, NULL};
    double root2 = root_brent(F2, 0.0, 1.0, 1e-7);
    printf("一元方程 cos(x)=x 的解: x = %.8f\n\n", root2);

    // 3. 求解二元 Rosenbrock 方程组
    struct rparams p = {1.0, 10.0};
    gsl_multiroot_function F_rosen = {rosenbrock_f, 2, &p};
    gsl_vector *x_rosen = gsl_vector_alloc(2);
    gsl_vector_set(x_rosen, 0, 10.0);
    gsl_vector_set(x_rosen, 1, 100000.0);
    printf("Rosenbrock 方程组求解:\n");
    multiroot_hybrids(F_rosen, x_rosen, 1e-7);
    gsl_vector_free(x_rosen);
    printf("\n");

    // 4. 求解二元 Powell 病态方程组
    gsl_multiroot_function F_powell = {powell_f, 2, NULL};
    gsl_vector *x_powell = gsl_vector_alloc(2);
    gsl_vector_set(x_powell, 0, 0.0);
    gsl_vector_set(x_powell, 1, 1.0);
    printf("Powell 病态方程组求解:\n");
    multiroot_hybrids(F_powell, x_powell, 1e-7);
    gsl_vector_free(x_powell);
    printf("\n");

    // 5. 求解三元 Helical 方程组
    gsl_multiroot_function F_helical = {helical_f, 3, NULL};
    gsl_vector *x_helical = gsl_vector_alloc(3);
    gsl_vector_set(x_helical, 0, -1.0);
    gsl_vector_set(x_helical, 1, 0.0);
    gsl_vector_set(x_helical, 2, 0.0);
    printf("Helical 方程组求解:\n");
    multiroot_hybrids(F_helical, x_helical, 1e-7);
    gsl_vector_free(x_helical);
    printf("\n");

    // 6. 求解四元 Powell 奇异方程组
    gsl_multiroot_function F_sing = {powellsing_f, 4, NULL};
    gsl_vector *x_sing = gsl_vector_alloc(4);
    gsl_vector_set(x_sing, 0, 3.0);
    gsl_vector_set(x_sing, 1, -1.0);
    gsl_vector_set(x_sing, 2, 0.0);
    gsl_vector_set(x_sing, 3, 1.0);
    printf("Powell 奇异方程组求解:\n");
    multiroot_hybrids(F_sing, x_sing, 1e-7);
    gsl_vector_free(x_sing);

    return 0;
}

运行结果如下:

附录:

相关推荐
zh路西法1 小时前
【宇树机器人强化学习】(三):OnPolicyRunner和VecEnv以及RolloutStorage的python实现与解析
开发语言·python·深度学习·机器学习·机器人
凤年徐1 小时前
优选算法——滑动窗口2
数据结构·c++·算法
sinat_255487812 小时前
FileReader/FileWriter
java·开发语言·jvm
清空mega2 小时前
网络程序设计入门第一章:Web、JSP、Tomcat 到底是什么?
开发语言·网络·php
历程里程碑2 小时前
37 线程安全单例模式深度解析
java·服务器·开发语言·前端·javascript·c++·排序算法
ambition202422 小时前
蓝桥杯“水质检测“问题:0-1 BFS算法的完整解析
c语言·数据结构·c++·算法·蓝桥杯·宽度优先
皙然2 小时前
深入解析 Java 中的 final 关键字
java·开发语言·算法
云深麋鹿2 小时前
C++ | 手搓一个string类
开发语言·c++·容器
阿里嘎多学长2 小时前
2026-03-15 GitHub 热点项目精选
开发语言·程序员·github·代码托管