Вот моя попытка реализовать программу, которая находит GCD из двух полиномов.
Я понимаю, что есть проблема в методе деления. Цикл while, уменьшающий степень результирующего полинома в division()
в некоторых случаях уходит в бесконечность, и я не могу понять, в каком именно.
Есть какие-нибудь подсказки о том, что здесь идет не так?
#include<iostream>
#include<stdlib.h>using namespace std;
//polynomial------------------------------
struct polynomial {
float *coeff;
int degree;
};
/*function declaration */
int get_data(polynomial *P);
int display(polynomial *P);
int division(polynomial *P, polynomial *Q, polynomial *H, polynomial *R);
int polcpy(polynomial *p, polynomial *q);
void GCDPol(polynomial *P,polynomial *Q, polynomial *R);
//GCD of two polynomials------------------
void GCDpol(polynomial *P,polynomial *Q, polynomial *R) {
polynomial *res, *v;
res = (polynomial *) calloc(1,sizeof(polynomial));
v = (polynomial *) calloc(1,sizeof(polynomial));
while(1) {
division(P, Q, v, R);
if(R->degree==0 && R->coeff[0]==0)
break;
else
polcpy(P,Q);
polcpy(Q,R);
}
polcpy(R,Q);
free(res);
free(v);
}
//pol copy--------------------------------
int polcpy(polynomial *p, polynomial *q) {
p->degree=q->degree;
p->coeff = new float[p->degree + 1];
for (int i=0; i<=p->degree; i++)
p->coeff[i]=q->coeff[i];
return 0;
}
//division--------------------------------
int division(polynomial *P, polynomial *Q, polynomial *H, polynomial *R) {
float u;
int x;
polynomial *nh, *nr;
nh = (polynomial *) calloc(1,sizeof(polynomial));
nr = (polynomial *) calloc(1,sizeof(polynomial));
/*Euclidian Long Division*/
polcpy(nr, P);
nh->degree = P->degree - Q->degree;
nh->coeff = new float[nh->degree + 1];
for (int i=nh->degree; i>=0; i--) {
nh->coeff[i] = nr->coeff[nr->degree] / Q->coeff[Q->degree];
for (int j=i; j <= nr->degree; j++) {
u = nh->coeff[i] * Q->coeff[j-i];
nr->coeff[j] = nr->coeff[j] - u;
}
if (nr->degree > 0)
nr->degree--;
}
/*Quotient*/
polcpy(H, nh);
/*Remainder*/
polcpy(R, nr);
while(R->coeff[R->degree] == 0) {
R->degree--;
}
free(nh);
free(nr);
return 0;
}
//display-------------------------------
int display(polynomial *P) {
int i, j;
for (i = P->degree; i >= 0; i--) {
cout << P->coeff[i] << "x^" << i;
if ((i - 1) != -1)
cout << "+";
}
cout << "\n";
return 0;
}
//get_data------------------------------
int get_data(polynomial *P) {
cout << "Enter Degree Of Polynomial:";
cin >> P->degree;
P->coeff = new float[P->degree + 1];
for (int i = P->degree; i >= 0; i--) {
cout << "Enter coefficient of x^" << i << ":";
cin >> P->coeff[i];
}
return 0;
}int main() {
polynomial *P, *Q, *R, *H;
P = (polynomial *) calloc(1,sizeof(polynomial));
Q = (polynomial *) calloc(1,sizeof(polynomial));
R = (polynomial *) calloc(1,sizeof(polynomial));
H = (polynomial *) calloc(1,sizeof(polynomial));
cout<<"GDC\n";
get_data(P);
get_data(Q);
cout << "Polynomial1:";
display(P);
cout << "Polynomial2:";
display(Q);
GCDpol(P,Q,R);
display(R);
free(R);
free(P);
free(Q);
free(H);
return 0;
}
Кажется вероятным, что линия
if(R->degree==0 && R->coeff[0]==0)
break;
это то, что сломано Ваши коэффициенты являются поплавками. Поскольку компьютеры (к сожалению) конечны, в ваших вычислениях с плавающей точкой будут небольшие ошибки. Код выходит из цикла while, только если коэффициент равен 0. Кажется вероятным, что на некоторых входах, хотя он должен делиться равномерно, вы получите R->coeff[0] = 0.0000000001
или какое-то другое очень маленькое значение, которое не совсем равно 0.
Попробуйте проверить, находится ли абсолютное значение в некотором очень небольшом допуске (что-то вроде 10 ^ -10 или 10 ^ -12.) Если вы действительно хотите точное значение, вам нужно изучить точные значения с плавающей точкой, что само по себе может червей.
(Если присмотреться к коду более внимательно, вы выполняете точные проверки на равенство и в других местах — все они должны быть изменены, чтобы проверка абсолютного значения была очень маленькой.)
while(R->coeff[R->degree] == 0) {
R->degree--;
}
Это идет плохо, если R
нулевой полином.
Эта библиотека C ++ реализует полиномиальное деление: PolynomialDivHang_test_no_hang