前言

Wassup guys,我是Edison

今天是C语言每日一练,第154天!

Let’s get it!


文章目录

  • 1. 问题描述
  • 2. 题目分析
  • 3. 算法设计
  • 4. 确定程序框架
  • 5. 迭代法求方程根
  • 6. 代码实现

1. 问题描述

编写用牛顿迭代法求方程根的函数。

方程为 a x2+ b x2+ c x + d = 0ax^2+bx^2+cx+d=0ax2+bx2+cx+d=0,系数a,b,c,d 由主函数输入。

xxx 111 附近的一个实根。求出根后,由主函数输出。

牛顿迭代法的公式是:− f( x 0) f ′( x 0) -\frac{f(x_0 )}{f'(x_0)} f(x0)f(x0) ,设迭代到 ∣x− x 0∣≤1 0 −5 |x-x_0|\leq10^{-5} xx0105 时结束。

2. 题目分析

牛顿迭代法是取 x0 x_0x0 之后,在这个基础上,找到比 x0 x_0x0 更接近的方程的根,一步一步迭代,从而找到更接近方程根的近似根。

rr rf(x)=0f(x)=0 f(x)=0 的根,选取 x 0x_0 x0 作为 rr r 初始近似值。

过点 ( x 0,f( x 0))(x_0, f(x_0)) (x0,f(x0)) 作为曲线 y=f(x)y=f(x) y=f(x) 的切线 LL L

LL L 的方程为 y=f( x 0)+ f ′( x 0)∗(x− x 0)y=f(x_0)+f'(x_0)*(x-x_0) y=f(x0)+f(x0)(xx0)

求出 L 与 x 轴交点的横坐标 x 1= x 0−f( x 0)/ f ′( x 0)x_1=x_0-f(x_0)/f'(x_0) x1=x0f(x0)/f(x0),称 xx xrr r 的一次近似值,

过点 ( x 1,f( x 1))(x_1,f(x_1)) (x1,f(x1)) 作为曲线 y=f(x)y=f(x) y=f(x) 的切线,并求该切线与 x 轴的横坐标 x 2= x 1−f( x 1)/ f ′( x 1)x_2=x_1-f(x_1)/f'(x_1) x2=x1f(x1)/f(x1),称 x 2x_2 x2rr r 的二次近似值,

重复以上过程,得 rr r 的近似值 x nx_n xn

上述过程即为牛顿迭代法的求解过程。

3. 算法设计

程序流程分析

(1) 在 11 1 附近找任一实数作为 x 0x_0 x0 的初值,我们取 1.51.5 1.5,即 x 0=1.5x_0=1.5 x0=1.5

(2) 用初值 x 0x_0 x0 代入方程中计算此时的 f( x 0)f(x_0) f(x0) f ′( x 0)f'(x_0) f(x0);程序中用变量 ff f 描述方程的值,用 fdfd fd 描述方程求导之后的值。

(3) 计算增量 h=f/fdh=f/fd h=f/fd

(4) 计算下一个 x:x= x 0−hx:x=x_0-h x:x=x0h

(5) 用新产生的 xx x 替换原来的 x ox_o xo,为下一次迭代做好准备。

(6) 若 ∣x− x 0∣>=1e−5|x-x_0|>=1e-5 xx0>=1e5,则转到第 (3) 步继续执行,否则转到步骤 (7)。

(7) 所求 xx x 就是方程 a x 3+b x 2+cx+d=0ax^3+bx^2+cx+d=0 ax3+bx2+cx+d=0 的根,将其输出。

本程序的编写既可用 while,也可用 do...while,二者得到的结果是一样的,只是在赋初值时稍有不同。

while 结构需要先判定条件,即先判断 ∣x− x 0∣>=1e−5|x-x_0|>=1e-5 xx0>=1e5 是否成立,这样对于 xx x x 0x_0 x0 我们要在 11 1 附近取两个不同的数值作为初值;

do...while 结构是先执行一次循环体,得到 xx x 的新值后再进行判定,这样程序开始只需给 xx x 赋初值。

这里我们采用 do...while 结构来实现。

4. 确定程序框架

程序的主体结构如下


由于程序中用到了绝对值函数 fabs() , 所以在程序的开始要加上头文件#include

流程图如下所示

5. 迭代法求方程根

编写程序时要注意的一点是判定 ∣ x − x0∣ > = 1 e − 5|x-x_0|>=1e-5xx0>=1e5

从牛顿迭代法的原理可以看出:迭代的实质就是越来越接近方程根的精确值,最初给 x 0x_0 x0 所赋初值与根的精确值是相差很多了,正是因为这个我们才需要不断地进行迭代,也就是程序中循环体的功能。

在经过一番迭代之后所求得的值之间的差别也越来越小,直到求得的某两个值的差的绝对值在某个范围之内时,便可结束迭代。

若我们把判定条件改为 ∣x− x 0∣<1e−5|x-x_0|<1e-5 xx0<1e5,则第一次的判断结果必为假,这样就不能进入循环体再次执行。

定义 solution()函数求方程的根。solution()函数的代码如下

6. 代码实现

完整代码

#include #include float solution(float a, float b, float c, float d){float x0, f, fd, h; float x = 1.5;do{x0 = x; f = a * x0 * x0 * x0 + b * x0 * x0 + c * x0 + d;fd = 3 * a * x0 * x0 + 2 * b * x0 + c;h = f / fd;x = x0 - h; } while (fabs(x-x0) >= 1e-5);return x;}int main(){float a, b, c, d; float x; printf("请输入方程的系数:");scanf("%f %f %f %f", &a, &b, &c, &d);x = solution(a, b, c, d);printf("\n");printf("所求方程的根为:x=%f\n", x);return 0;}

运行结果

代码解释