昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

C语言版+非线性方程数值求解

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>

// 定义需要求解的非线性方程(示例:x^3 - 2x - 5 = 0)
/**
 * @brief 计算给定x值的立方函数结果
 *
 * 函数实现公式:f(x) = x³ - 2x - 5
 *
 * @param x 输入的自变量值
 * @return double 计算结果值
 */
/**
 * @brief 计算给定x值的立方函数结果
 *
 * 函数计算x的立方减去2倍x再减5的值,即f(x) = x³ - 2x - 5
 *
 * @param x 输入的双精度浮点数值
 * @return double 计算结果值
 */
double f(double x) {
    return x * x * x - 2 * x - 5;
}

// 定义方程的导数(示例:3x^2 - 2)
double df(double x) {
    return 3*x*x - 2;
}

// 二分法求解
double bisection(double a, double b, double tol) {
    if (f(a) * f(b) >= 0) {
        printf("区间 [a, b] 无效,请确保 f(a) 和 f(b) 符号相反。\n");
        return NAN; // 返回非数字表示错误
    }

    double c;
    while ((b - a) >= tol) {
        c = (a + b) / 2;
        if (f(c) == 0.0) {
            break;
        } else if (f(c) * f(a) < 0) {
            b = c;
        } else {
            a = c;
        }
    }
    return c;
}

// 牛顿法求解
double newton(double x0, double tol) {
    double x = x0;
    double h = f(x) / df(x);
    while (fabs(h) >= tol) {
        h = f(x) / df(x);
        x = x - h;
    }
    return x;
}

// 弦截法求解
double secant(double x0, double x1, double tol) {
    double x2;
    while (fabs(x1 - x0) >= tol) {
        x2 = x1 - f(x1) * (x1 - x0) / (f(x1) - f(x0));
        x0 = x1;
        x1 = x2;
    }
    return x1;
}

// 割线法求解
double secant_method(double x0, double x1, double tol) {
    double x2;
    while (fabs(x1 - x0) >= tol) {
        x2 = x1 - f(x1) * (x1 - x0) / (f(x1) - f(x0));
        x0 = x1;
        x1 = x2;
    }
    return x1;
}

// 蒙特卡洛方法求解
double monte_carlo(double a, double b, int samples, double tol) {
    srand(time(NULL)); // 初始化随机数种子
    double min_x = a;
    double min_f = fabs(f(a));

    for (int i = 0; i < samples; i++) {
        double x = a + (double)rand() / RAND_MAX * (b - a);
        double current_f = fabs(f(x));
        if (current_f < min_f) {
            min_f = current_f;
            min_x = x;
        }
        if (min_f < tol) {
            break;
        }
    }
    return min_x;
}

// 梯度下降法求解(最小化 f(x)^2)
double gradient_descent(double x0, double learning_rate, double tol) {
    double x = x0;
    double step;
    int max_iter = 10000; // 最大迭代次数
    int iter = 0;
    
    while (iter < max_iter) {
        double fx = f(x);
        double gradient = 2 * fx * df(x); // 最小化 f(x)^2 的梯度
        step = learning_rate * gradient;
        x = x - step;
        
        // 动态调整学习率
        if (fabs(gradient) > 1.0) {
            learning_rate = 0.0001; // 大梯度时使用更小的学习率
        } else {
            learning_rate = 0.001; // 小梯度时恢复稍大的学习率
        }
        
        // 收敛条件:函数值接近零且步长足够小
        if (fabs(fx) < tol && fabs(step) < tol) {
            break;
        }
        iter++;
    }
    return x;
}

int main() {
    double a = 1.0, b = 3.0; // 初始区间
    double tol = 1e-6;       // 容差
    double root_bisection = bisection(a, b, tol);
    printf("二分法解: %.6f\n", root_bisection);

    double x0 = 2.0; // 牛顿法的初始猜测值
    double root_newton = newton(x0, tol);
    printf("牛顿法解: %.6f\n", root_newton);

    double x1 = 1.5, x2 = 2.5; // 弦截法的初始猜测值
    double root_secant = secant(x1, x2, tol);
    printf("弦截法解: %.6f\n", root_secant);

    double x3 = 1.0, x4 = 2.0; // 割线法的初始猜测值
    double root_secant_method = secant_method(x3, x4, tol);
    printf("割线法解: %.6f\n", root_secant_method);

    int samples = 10000; // 蒙特卡洛方法的采样次数
    double root_monte_carlo = monte_carlo(a, b, samples, tol);
    printf("蒙特卡洛方法解: %.6f\n", root_monte_carlo);

    double learning_rate = 0.01; // 梯度下降法的学习率
    double x5 = 2.0; // 梯度下降法的初始猜测值
    double root_gradient_descent = gradient_descent(x5, learning_rate, tol);
    printf("梯度下降法解: %.6f\n", root_gradient_descent);
    return 0;
}


posted on 2025-09-11 21:55  Indian_Mysore  阅读(10)  评论(0)    收藏  举报

导航