乐乎论坛_多项式 求根的算法和程序

2020-08-01 作者 : 浏览量:880
多项式 求根的算法和程序
这题可二分法步进试探求解然这里说的二分法不是像谭书上的那么简了,不是一个f(x1)*f(x2)<0就可以确定的。因为他举例子是在一个单调区间求根,而这里是要求出所有解,区间不一定是单调的。上次我发了一个类似的程序有人评价说不好,那不过是他根本没理解非单调区间找出所有根和单调区间找一个根难度根本不可比较,说明他根本没理解算法目的。

这里的思路是先定一个区间[a,b]然后从a开始以步长h在[a,a+h]内搜索是否有根,然后[a+h,a+2*h],直到区间右端到达b为止。a,b如何大概确定?可以利用高等数学中的高阶导数求出多项式何时恒为正或恒为负决定,这个不难。显然a,b的区间越小程序执行越快。所以a,b尽量定准确一些。程序中定得比较大[-100,150],实际改得越精确越好,当然不能漏根。同时h越小计算时间越长,但是结果精度越高,所以取值要以程序要求的精确度和执行时间综合考虑,这里取0.1。

同时为了提高计算速度,使用了著名的霍纳求值法。即求3x^3-5x^2+x+1转化为求((3x-5)x+1)x+1,因为第一种求法要做7次乘法而带括号的求法只用做3次乘法。当然如果多项式函数是奇函数或偶函数还可以简化[a,b]区间。
程序中设定了一个多项式,实际更改为所求多项式即可。
一个完整的c程序如下,程序在win-tc和Dev-c++下都调试通过。
#include
#include
#include

double Equation(double x)
{
double z;
z=(((((x-5.0)*x+3.0)*x+1.0)*x-7.0)*x+7.0)*x-20.0;/*更改为实际多项式*/
return(z);
}

int BinSearchRoot(double a,double b,double h,double eps,double x[],int m) /*用二分法计算非线性方程的实根*/
/*参数意义:
a 要求的根的下界
b 要求的根的上界,即:所求的根落在区间 [a,b]之内
h 递进的步长
eps 精度
x 根的值
m 预计的根的个数*/
{
int n,js;
double z,y,z1,y1,z0,y0;
n=0; z=a; y=Equation(z);
while ((z<=b+h/2.0)&&(n!=m)) /*对给定步长的子区间进行搜索*/
{
if (fabs(y){
n=n+1;
x[n-1]=z;
z=z+h/2.0;
y=Equation(z);
}
else /*当前点不是方程的根*/
{
z1=z+h;
y1=Equation(z1);
if (fabs(y1){
n=n+1;
x[n-1]=z1;
z=z1+h/2.0;
y=Equation(z);
}
else if (y*y1>0.0) /*该区间内无根*/
{ y=y1; z=z1;}
else /*该区间内有根*/
{
js=0;/*标志,0表示未找到根,1表示已经确定了根*/
while (js==0)
{
if (fabs(z1-z){
n=n+1;
x[n-1]=(z1+z)/2.0; /*把区间的中位值作为根*/
z=z1+h/2.0; /*把寻找的位置放到下一个区间内*/
y=Equation(z);
js=1; /*在当前区间内已经找到了根*/
}
else /*区间比给定的精度大,则进行二分*/
{
z0=(z1+z)/2.0; /*区间二分*/
y0=Equation(z0);
if (fabs(y0){
x[n]=z0;
n=n+1;
js=1;
z=z0+h/2.0;
y=Equation(z);
}
else if ((y*y0)<0.0) /*[z,z0]内有根*/
{ z1=z0; y1=y0;}
else { z=z0; y=y0;}
}
}
}
}
}
return(n); /*返回根的个数*/
}

int main()
{
int i,n;
static int m=6;
static double x[6];
system("cls");
printf("\nThe Nonlinear function is:\n");
printf("\nf(x)=(((((x-5.0)*x+3.0)*x+1.0)*x-7.0)*x+7.0)*x-20.0\n"); /*更改为实际多项式*/
n=BinSearchRoot(-100.0,150.0,0.1,0.000001,x,m);
printf("\nThe function has %d roots, they are:\n",n);/*输出根的个数*/
for (i=0; i<=n-1; i++)
printf("x(%d)=%10.7f\n",i,x[i]);
system("pause");
return 0;
}

后记:百度是个比较浮躁的地方,个别人说三道四,我一笑了之。真正正确的东西他理解不了,只能说明他还没达到那个层次,要从自身找原因。

显然二分法是不能解决虚根问题的。

这题可以用二分法步进试探求解。当然这里二分法不是像谭浩上的那么简单明了,不个f(x1)*f(x2)<0就可以确定的。因为他举例子是在一个单调区间求根,而这里是要求出所有解,区间不一定是单调的。上次我发了一个类似的程序有人评价说不好,那不过是他根本没理解非单调区间找出所有根和单调区间找一个根难度根本不可比较,说明他根本没理解算法目的。

这里的思路是先定一个区间[a,b]然后从a开始以步长h在[a,a+h]内搜索是否有根,然后[a+h,a+2*h],直到区间右端到达b为止。a,b如何大概确定?可以利用高等数学中的高阶导数求出多项式何时恒为正或恒为负决定,这个不难。显然a,b的区间越小程序执行越快。所以a,b尽量定准确一些。程序中定得比较大[-100,150],实际改得越精确越好,当然不能漏根。同时h越小计算时间越长,但是结果精度越高,所以取值要以程序要求的精确度和执行时间综合考虑,这里取0.1。

同时为了提高计算速度,使用了著名的霍纳求值法。即求3x^3-5x^2+x+1转化为求((3x-5)x+1)x+1,因为第一种求法要做7次乘法而带括号的求法只用做3次乘法。当然如果多项式函数是奇函数或偶函数还可以简化[a,b]区间。
程序中设定了一个多项式,实际更改为所求多项式即可。
一个完整的c程序如下,程序在win-tc和Dev-c++下都调试通过。
#include
#include
#include

double Equation(double x)
{
double z;
z=(((((x-5.0)*x+3.0)*x+1.0)*x-7.0)*x+7.0)*x-20.0;/*更改为实际多项式*/
return(z);
}

int BinSearchRoot(double a,double b,double h,double eps,double x[],int m) /*用二分法计算非线性方程的实根*/
/*参数意义:
a 要求的根的下界
b 要求的根的上界,即:所求的根落在区间 [a,b]之内
h 递进的步长
eps 精度
x 根的值
m 预计的根的个数*/
{
int n,js;
double z,y,z1,y1,z0,y0;
n=0; z=a; y=Equation(z);
while ((z<=b+h/2.0)&&(n!=m)) /*对给定步长的子区间进行搜索*/
{
if (fabs(y){
n=n+1;
x[n-1]=z;
z=z+h/2.0;
y=Equation(z);
}
else /*当前点不是方程的根*/
{
z1=z+h;
y1=Equation(z1);
if (fabs(y1){
n=n+1;
x[n-1]=z1;
z=z1+h/2.0;
y=Equation(z);
}
else if (y*y1>0.0) /*该区间内无根*/
{ y=y1; z=z1;}
else /*该区间内有根*/
{
js=0;/*标志,0表示未找到根,1表示已经确定了根*/
while (js==0)
{
if (fabs(z1-z){
n=n+1;
x[n-1]=(z1+z)/2.0; /*把区间的中位值作为根*/
z=z1+h/2.0; /*把寻找的位置放到下一个区间内*/
y=Equation(z);
js=1; /*在当前区间内已经找到了根*/
}
else /*区间比给定的精度大,则进行二分*/
{
z0=(z1+z)/2.0; /*区间二分*/
y0=Equation(z0);
if (fabs(y0){
x[n]=z0;
n=n+1;
js=1;
z=z0+h/2.0;
y=Equation(z);
}
else if ((y*y0)<0.0) /*[z,z0]内有根*/
{ z1=z0; y1=y0;}
else { z=z0; y=y0;}
}
}
}
}
}
return(n); /*返回根的个数*/
}

int main()
{
int i,n;
static int m=6;
static double x[6];
system("cls");
printf("\nThe Nonlinear function is:\n");
printf("\nf(x)=(((((x-5.0)*x+3.0)*x+1.0)*x-7.0)*x+7.0)*x-20.0\n"); /*更改为实际多项式*/
n=BinSearchRoot(-100.0,150.0,0.1,0.000001,x,m);
printf("\nThe function has %d roots, they are:\n",n);/*输出根的个数*/
for (i=0; i<=n-1; i++)
printf("x(%d)=%10.7f\n",i,x[i]);
system("pause");
return 0;

显然二分法是不能解决虚根问题的。赚积分
是否有多项式时间算法计算给定的分解,并且对于一些
数,整数分解(素因数分问题是指:给出一个正整数,将其写个约数的乘积。例给出45这个数,它可以分解成32 ×5。根据算术基本定理,这样的分解结果应该是独一无二的。这个问题在代数学、密码学、计算复杂性理论和量子计算机等领域中有重要意义。
2005年,作为公共研究一部分的有663个二进制数位之长的RSA-200已经被一种一般用途的方法所分解。

如果一个大的,有n个二进制数位长度的数是两个差不多大小相等的约数的乘积,现在还没有很好的算法来以多项式时间复杂度分解它。

这就意味着没有已知算法可以在O(nk)(k为常数)的时间内分解它。但是现在的算法也是比Θ(en)快的。换句话说,现在我们已知最好的算法比指数数量级时间要快,比多项式数量级时间要慢。已知最好的渐近线运行时间是普通数域筛选法(GNFS)。时间是:

对于平常的计算机,GNFS是我们已知最好的对付n个二进制数位大约数的方法。不过,对于量子计算机, 彼得·秀尔在1994年发现了一种可以用多项式时间来解决这个问题的算法。如果大的量子计算机建立起来,这将对密码学有很重要的意义。这个算法在时间上只需要O(n3),空间只要O(n)就可以了。 构造出这样一个算法只需要2n量子位。2001年,第一个7量子位的量子计算机第一个运行这个算法,它分解的数是15

如果想获得最新消息,请你上wikipedia百科,英文版。定义:若存在一个常数C,使得对于所有n>=0,都有|f(n)|
多项式算法
(1)9X+4
(2)X-12
(3)3X平方-8X-13
(4)5X平方-23X+9
(5)3X平方-14X+9
(6)X的3+X平方+4+4X
(7)5X+1
(8)5X平方+5X-10
如果你愿意 你把有要问的弄出来 可恶 那个人快1秒!!!!!!!!!!!!!!!!!!!!!!!!1.9X+4

2.X-12

3.3X-8X-13

4.5X平方-23X+9

5.3X平方-14X+9

6.同上

7.X三次方+4X+X平方+4

8.5X+1

9.5X平方+5X-10

过程啊?不太好打类,就是把他们都先乘出来后合并同类项嘛,加油,你能行的二楼正确9X+4
X-12
3X的平方-8X-13
5X的平方-23X+9
3X的平方-14X+9
X的立方+X的平方+4X+4
5X+1
5X的平方+5X-10A:6x-2+3x+6=9x+4
B:5x-10-4x-2=x-12
C:3x2次-6x-3-2x-10=3x的2次方-8x-13
D:8x的2次方-20x+12-3x的2次方-3x-3=5x的2次方-23x+9
E:18x的2次方-24x+24-15x的2次方+10x-15=3x的2次方-14x+9

A:原式=x的3次方+4x+x的2次方+4=x的3次方+x的2次方+4x+4
B:原式=2x的2次方+3x+2x+3-2x的2次方-2=5x+1
C:原式=2x的2次方+4x-5x-10+3x+6=2x的2次方+2x-4(1)9X+4
(2)X-12
(3)3X平方-8X-13
(4)5X平方-23X+9
(5)3X平方-14X+9
(6)X的3次方+X平方+4+4X
(7)5X+1
(8)5X平方+5X-10
两个以单链表作存储结构的一元多项式A和B,编写算法将多项式A和B相加,要求利用原表的结点空间和多项式。
#include
#include
#include
typedef struct
{
float coef;
int expn;
}
ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}
LNode,*LinkList;
LinkList InitList()//创表
{
LinkList L;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
return(L);
}
void InsLNode(LinkList L,ElemType x)//插入链表函数
{
LinkList s,p;
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
p=L;
while(p->next)
p=p->next;
s->next=NULL;
p->next=s;
}
void AddPolyn(LinkList pa,LinkList pb)//多项式相
{
LinkList ha,hb,qa,qb;
float sum;int a,b;
ha=pa;hb=pb;
qa=ha->next;qb=hb->next;
while(qa&&qb)
{
a=qa->data.expn;b=qb->data.expn;;
if(a{
ha=qa;
qa=qa->next;
}
if(a==b)
{
sum=qa->data.coef+qb->data.coef;
if(sum!=0)
{
qa->data.coef=sum;
ha=qa;
qa=qa->next;
hb->next=qb->next;
free(qb);
qb=hb->next;
}
else
{
ha->next=qa->next;
free(qa);qa=ha->next;
hb->next=qb->next;
free(qb);
qb=hb->next;
}
}
if(a>b)
{
hb->next=qb->next;qb->next=ha->next;
ha->next=qb;
ha=qb;
free(qb);
qb=hb->next;
}
}
if(qb)
ha->next=qb;
free(hb);
}

void Invert(LinkList L)//逆序输出链表
{LinkList p,q,r;
p=L->next;
q=p->next;
while(q!=NULL)
{r=q->next;
q->next=p;
p=q;
q=r;
}L->next->next=NULL;
L->next=p;
}

void Print(LinkList L)//输出多项式
{
LinkList p;
p=L->next;
while(p->next)
{
printf("%fx^%d+",p->data.coef,p->data.expn);
p=p->next;
}
printf("%fx^%d",p->data.coef,p->data.expn);
}
void main()
{
LinkList La,Lb;ElemType c;
int a,i;
La=InitList();
Lb= InitList();
printf("La的项数:");
scanf("%d",&a);
for(i=0;i{
printf("输入La%d项系数:",i+1);
scanf("%f",&c.coef);
printf("输入La第%d项指数:",i+1);
scanf("%d",&c.expn);
InsLNode(La,c);
}
printf("输入Lb的项数:");
scanf("%d",&a);
for(i=0;i{
printf("输入Lb第 %d项系数:",i+1);
scanf("%f",&c.coef);
printf("输入Lb第%d项指数:",i+1);
scanf("%d",&c.expn);
InsLNode(Lb,c);
}
printf("La为");printf("\n");
Print(La);printf("\n");
printf("Lb为");printf("\n");
Print(Lb);printf("\n");
printf("多项式和为");printf("\n");
AddPolyn(La,Lb);
Invert(La);
Print(La);
}
//以前做过一个,参考一下,输入多项式的时候根据指数从小到大输入