一元三次方程的求解问题
牛顿迭代法是牛顿在17世纪提出的一种求解方程f(x)=0.多数方程不存在求根公式,从而求精确根非常困难,甚至不可能,从而寻找方程的近似根就显得特别重要。
设r是f(x)=0的根,选取x0作为r初始近似值,过点(x0,f(x0))做曲线y=f(x)的切线L,L的方程为y=f(x0)+f'(x0)(x-x0),求出L与x轴交点的横坐标 x1=x0-f(x0)/f'(x0),称x1为r的一次近似值,过点(x1,f(x1))做曲线y=f(x)的切线,并求该切线与x轴的横坐标 x2=x1-f(x1)/f'(x1)称x2为r的二次近似值,重复以上过程,得r的近似值序列{Xn},其中Xn+1=Xn-f(Xn)/f'(Xn),称为r的n+1次近似值。上式称为牛顿迭代公式。
/*
用牛顿迭代法求下面方程
x*x*x-5*x*x+16*x-80=0的实根的过程是:
1.你想在谁附近求解,这个范围或者这个数值大多是题目已经给定了的(本例是根据输入的数值来计算的)
2.令f(x)=x*x*x-5*x*x+16*x-80
3.x1=X
4.求f(x1)
5.对f(x)求导,得到f1(x),求f1(x1)
6.调整x,使x=x1-f(x1)/f1(x1)
7.符合条件x-x1>1e-5,转到第3步
8.不符合条件x-x1>1e-5,则x1就是我们要求的实根
*/
解法思路:
先把求与X轴交点坐标公式放着免得忘记了
x= x1f(x2)-x2f(x1)/f(x2)-f(x1)
之后比较x1的y1值和x2的y2值,如果两个为异号,那么两个x之间一定有方程的根
如果同号,那么继续输入直到异号为止
这个时候用求交点坐标公式求出交点坐标x,它的y值同样代入求出
再次比较y与y1值,如果异号那么x与x1之间必有方程根
如果同号那么x与x2之间必有方程根
循环以上直到y的绝对值小于一个非常小的数,也就近似为0的时候,输出x值既为方程根......
理好了解法思路就不怕了,因为这个程序的关键就是我没学过解法,现在解法清楚了就开始编了
写了很多的函数,对我来说很复杂,所以注释比较多,省的以后自己都看不懂了......
书上给的例子方程式x^3-5x^2+16x-80=0 给出的一个解x=5,图2反应出来了......
#include <stdio.h>
#include <math.h>
#include <conio.h>
float a,b,c,d; //定义外部变量,使全局可以调用
float f(float x) //x函数
{
float y;
y=a*x*x*x+b*x*x+c*x+d;
return y;
}
float xpoint(float x1,float x2) //求弦与x轴交点坐标
{
float y;
y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1));
return y;
}
float root(float x1,float x2) //求根函数
{
float x,y,y1;
y1=f(x1); //y1为x1纵坐标
do
{
x=xpoint(x1,x2); //求x1与x2之间弦与x轴交点赋值于x
y=f(x); //代入方程中求得y
if(y*y1>0) //判断y与y1是否同号
{
x1=x;
y1=y;
}
else
x2=x;
}
while(fabs(y)>=0.00001); //设定精度
return(x);
}
void main() //主函数
{
float x1,x2,f1,f2,x;
printf("请输入一元三次方程标准形式ax^3+bx^2+cx+d=0中 ");
printf("a b c d的值,用空格隔开/n");
scanf("%f %f %f %f",&a,&b,&c,&d); //获取abcd值并赋值
do
{
printf("输入x1 x2值,用空格隔开:/n");
scanf("%f %f",&x1,&x2);
f1=f(x1);
f2=f(x2);
if(f1*f2>=0)
printf("x1 x2之间无方程根,请重新输入/n");
}
while(f1*f2>=0); //do...while函数为了得到x1与x2的函数值为异号,这样x1 x2中才有根
x=root(x1,x2); //将x1 x2送到求根函数中返回值赋到x中
printf("方程中的一个根为%g/n",x);
getch();
}
运行截图:
附:两分法解方程 求一个实根
算法:
用两分法求方程 y=f(x) = 0 的近似根。
找两个近似根 x1和 x2,使有
y1和y2异号,如
y1< 0, y2> 0
求新的近似根, x = (x1 + x2)/2
若 y=f(x)<0, 则 x1= x; y1= f(x);
否则, x2= x; y2= f(x);
根所在的区间缩小一半。
重复计算新的近似根并估计偏差
直至 | x2 – x1|<1e-10。

牛顿法解方程 求一个实根
算法:方程y=f(x)=0
求在x0 附近的一个实根。
选一个近似根x0,求y0 =f(x0);
过y0作f(x)的切线,交横轴于x1,
以 x1为新的近似根,重复上述步骤...

一元三次方程的求解问题
二分法的应用
[问题描述]
有形如:ax3+bx2+cx+d=0这样的一个一元三次方程。给出该方程中各项的系数(a, 微星网络
b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间), 本文来自微星网络
且根与根之差的绝对值≥1。
微星网络
要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点 微星网络
后2位。 ie210.com
微星网络
提示;记方程f(x)=0,若存在2个数x1和x2,且x1 < x2,f(x1)*f(x2) < 0,
微星网络,真诚永远,创意无限
则在(x1,x2)之间一定有一个根。 [样例]
输入: 1 -5 -4 20
微星网络,真诚永远,创意无限
输出:-2.00 2.00 5.00 ie210.cn
问题分析
根据题意,三次方程 ax^3+bx^2+cx+d=0在区间[-100,100]有3个不等实根,不妨设这3个实根分别为x1,x2,x3,且x1<x2<x3,则方程可表示为a(x-x1)(x-x2)(x-x3)=0;于是,求解这3个实根,可转化为求函数f(x)= a(x-x1)(x-x2)(x-x3)图像与x轴交点的横坐标。如图:
二分法:
微星网络,真诚永远,创意无限
1. 确定根的区间 本文来自微星网络
考虑在什么样的区间内会有根,由于题目给出了所有的根都在-100到100之间,且根与根之间的差不小于1的限制条件,可知,在[-100,100],[-99,-98],…[99,100],[100,100]这201个区间内,每个区间内至多只能存在一个根,这样除去区间[100,100]外,其他区间[a,a+1],要么f(a)=0,要么f(a)×f(a+1)<0时这个方程在此区间内才有解。
2. 求方程的根
确定了方程f(x)=0在区间(a,b)内如果有且只有一个根,那么我们可以有逐步缩小根可能存在的范围的方法确定出某精度下根的数值。本题规定根的精度是0.01,下面采用二分法求区间(a,b)内方程的根,过程如下: ie210.cn
(1) 取当前可能存在解的区间(a,b);
(2) 若a+0.001>b或 f((a+b)/2)=0,则可确定根为(a+b)/2并退出过程;
(3) 若f(a)×f((a+b)/2)<0,则根在区间(a, (a+b)/2)中,故对区间(a, (a+b)/2)重复该过程;
(4) 若f(a)× f((a+b)/2)>0,则必然有 f((a+b)/2)×f(b)<0,也就是说根在((a+b)/2,b)中,应该对此区间重复该过程。
二分法求根的算法如下:
二分法的基本思路是:任意两个点x1和x2,判断区间(x1,x2)内有无一个实根,如果f(x1)与f(x2)符号相反,则说明有一实根。接着取(x1,x2)的中点x,检查f(x)和f(x2)是否同号,如果不同号,说明实根在(x,x2)之间,如果同号,在比较(x1,x),这样就将范围缩小一半,然后按上述方法不断的递归调用,直到区间相当小(找出根为止)! 比如用二分法求f(x)=x^3-6x-1=0的实根。 代码如下(已调试): #include "math.h" main() { float x,x1,x2; float F(float x,float x1,float x2); printf("请输入区间[x1,x2]/n"); scanf("%f%f",&x1,&x2); printf("x=%f/n",F(x,x1,x2)); } float F(float x,float x1,float x2) { float f,f1,f2; do { f1=pow(x1,3)-6*x1-1.0; f2=pow(x2,3)-6*x2-1.0; }while(f1*f2>0); //确保输入的x1,x2使得f1,f2符号相反 do { x=(x1+x2)/2; //求x1,x2的中点 f=pow(x,3)-6*x-1.0; if(f1*f>0) //当f与f1符号相同时 {x1=x;f1=f;} else if(f2*f>0) //当f与f2符号相同时 {x2=x;f2=f;} }while(fabs(f)>1e-6); //判断条件fabs(f)>1e-6的意思是f的值非常0 return x; }