[C++] Klasa wielomian i obliczanie miejsc zerowych - problem

0

Witam, mam oto taki problem: Mam napisać program - klasę wielomian, który jest odpowiedzialny na wprowadzanie współczynników i stopnia wielomianu, wykonywać operacje na tych wielomianach +,-,*. Dodatkowo musi obliczać miejsca zerowe wielomianu... I tutaj pojawia się problem. Bo o ile z pomocą kolegi napisaliśmy te wszystkie założenia to nie umiemy sobie poradzić z oblicaniem miejsc zerowych...
Prosiłbym o pomoc, dziękuję za zainteresowanie. Pozdrawiam

Oto pliki programu:

main.cpp

#include <iostream>
#include "wielomian.h"
using namespace std;



int main()
{
	int stopien;
	cout<<"Podaj stopien wielomianu"<<endl;
	cin>>stopien;
	wielomian obiekt1(stopien);

	wielomian *wsk;
	wsk = new wielomian(10);
	

	cout<<"Podaj stopien  drugiego wielomianu"<<endl;
	cin>>stopien;
	wielomian obiekt2(stopien);
	cin>>obiekt2;

	cout<<endl<<endl;
	cout<<obiekt1;

	cout<<endl<<endl;
	cout<<obiekt2;

	*wsk=obiekt1-obiekt2;
	cout<<endl<<endl;
	cout<<obiekt1;

if(obiekt1==obiekt2)
{
	cout<<"Wielomiany sa rowne"<<endl;
}
else
{
	cout<<"wielomiany sa rozne"<<endl;
}

cout<<endl<<endl;
cout<<*wsk;

	return 0;
}

wielomian.cpp

#include "wielomian.h"

using namespace std;

/****************************************
Konstruktor domyslny ! ! ! !
Jesli zostanie utworzony obiekt bez parametrow, to konstruktor domyslny zostanie wywolany.
Nie mialem pomyslu co w nim powinno sie znalezc, wiec zalozylem, iz jesli zostanie wywolany bez parametru, to stopien
wielomianu wynosic bedzie 1, czyli tak naprawde bedzie to prosta rownolegla do osi ox.
*****************************************/
wielomian::wielomian()
{
	stopien=0;
	wsp=new float[1];
	*wsp=3;
	losuj_wspolczynniki();
}


/***************************************
Konstruktor z jednym parametrem
Konstruktor ten przyjmuje tylko jeden parametr, stopien wielomianu, i dla zadanego stopnia, tworzy dynamiczna tablice
***************************************/
wielomian::wielomian(int _stopien)
{
stopien=_stopien+1;
wsp=new float[stopien];
losuj_wspolczynniki();
}



/****************************************
Destruktor ! ! ! !
Zwalniamy w nim pamiec, czyli tablice wspolczynnikow
*****************************************/
wielomian::~wielomian()
{
	delete [] wsp;
}

/****************************************
Konstruktor kopiujacy ! ! ! !
Z obiektu wzor (wyslanego przez referencje! dla bezpieczenstwa dajemy slowko const, aby nie zmodyfikowac wzoru) kopiujemy 
wszystkie wartosci i przydzielamy je do nowego obiektu. Najpierw kopiujemy stopien, a nastepnie wskaznik na tablice floatow.
memcpy sluzy do skopiowania pamieci z jednego miejsca w drugie. Trzeci parametr to rozmiar pamieci do skopiowania
****************************************/
wielomian::wielomian (const wielomian &wzor)
{
	stopien=wzor.stopien;
	wsp = new float [stopien];
	memcpy(wsp, wzor.wsp, (stopien*sizeof(float)));
}


void wielomian::losuj_wspolczynniki()
{
time_t t;
int i=0;
srand((unsigned) time(&t)); 

	while(i<stopien)
	{
		*(wsp+i)=(float)(rand()%20-10); //Zakres -10 do 10
		i++;
	} 
	
}



/********************************************
Przeciazony operator << odpowiedzialny za wypisanie wzoru wielomianu
Wewnatrz niego znajduja sie 3 ify, sprawdzajace, czy dany wspolczynnik jest <, > lub = 0.
Potrzebne jest to, aby dobrze wypisac postac wielomianu
********************************************/
ostream & operator<<(ostream &wyjscie, const wielomian & obiekt)
{
		int i=0;
	wyjscie<<endl<<"Wielomian ma postac:"<<endl;
		while(i<obiekt.stopien)
		{
		if(((*((obiekt.wsp)+i))>0) && i!=0)
			wyjscie<<"+"<<(*((obiekt.wsp)+i))<<"x^"<<obiekt.stopien-i-1<<" ";
		
		if(((*((obiekt.wsp)+i))>0) && i==0)
			wyjscie<<(*((obiekt.wsp)+i))<<"x^"<<obiekt.stopien-i-1<<" ";

		if((*((obiekt.wsp)+i))<0)
			wyjscie<<(*((obiekt.wsp)+i))<<"x^"<<obiekt.stopien-i-1<<" ";	

		i++;
		} 
	wyjscie<<endl;
	return wyjscie;
}

/********************************************
Przeciazony zaprzyjazniony operator >> odpowiedzialny za wprowadzenie wzoru wielomianu
********************************************/
istream & operator>>(istream &wejscie,  wielomian & obiekt)
{
	cout<<endl<<"Podaj "<<obiekt.stopien<<" wspolczynnikow wielomianu zaczynajac od tego przy najwyzszym wykladniku"<<endl;
	for(int i=0; i<obiekt.stopien; i++)
	{
		cout<<"x^"<<obiekt.stopien-i-1<<" : ";
	wejscie >> *((obiekt.wsp)+i) ;
	}
	return wejscie;
}



/********************************************
Przeciazony operator + odpowiedzialny za dodawanie 2 wielomianow
W pierwszej kolejnosci sprawdza on, czy drugi wielomian, ktory dodajemy, jest stopnia mniejszego od pierwszego wielomianu
Jesli tak, to poprostu dodajemy, jesli nie, musimy skorzystac z wiekszej tablicy na wspolczynniki wielomianu
********************************************/
wielomian wielomian::operator+ (wielomian & liczba)
	{
		int i=liczba.stopien;
		if(stopien>=liczba.stopien)
		{
			for(i=liczba.stopien; i>0; i--)
			{
				*(wsp+stopien - i)=(*(wsp+ stopien -i)) + (*((liczba.wsp)+liczba.stopien -i) );
				
			}
			
		}
		else
		{
			wielomian temp(liczba.stopien); //pomocniczy obiekt, aby nie stracic danych
			for(int i=liczba.stopien; i>=0; i--)
			{
				if(i>stopien)
				{
					(*((temp.wsp)+liczba.stopien - i))=(*((liczba.wsp)+liczba.stopien -i) );
				}
				else
				{
					(*((temp.wsp)+liczba.stopien - i))=(*(wsp+ stopien -i)) + (*((liczba.wsp)+liczba.stopien -i) );
				}
			}
				delete [] wsp;
				stopien=liczba.stopien;
				wsp = new float [liczba.stopien];
				memcpy(wsp, temp.wsp, (liczba.stopien*sizeof(float)));
		}

		return *this;
	}



/********************************************
Przeciazony operator - odpowiedzialny za dodawanie 2 wielomianow
W pierwszej kolejnosci sprawdza on, czy drugi wielomian, ktory odejmujemy, jest stopnia mniejszego od pierwszego wielomianu
Jesli tak, to poprostu odejmujemy, jesli nie, musimy skorzystac z wiekszej tablicy na wspolczynniki wielomianu
********************************************/
wielomian wielomian::operator- (wielomian & liczba)
	{
		int i=liczba.stopien;
		if(stopien>=liczba.stopien)
		{
			for(i=liczba.stopien; i>0; i--)
			{
				*(wsp+stopien - i)=(*(wsp+ stopien -i)) - (*((liczba.wsp)+liczba.stopien -i) );
				
			}
			
		}
		else
		{
			wielomian temp(liczba.stopien); //pomocniczy obiekt, aby nie stracic danych
			for(int i=liczba.stopien; i>=0; i--)
			{
				if(i>stopien)
				{
					(*((temp.wsp)+liczba.stopien - i))=(*((liczba.wsp)+liczba.stopien -i) );
				}
				else
				{
					(*((temp.wsp)+liczba.stopien - i))=(*(wsp+ stopien -i)) - (*((liczba.wsp)+liczba.stopien -i) );
				}
			}
				delete [] wsp;
				stopien=liczba.stopien;				wsp = new float [liczba.stopien];
				memcpy(wsp, temp.wsp, (liczba.stopien*sizeof(float)));
		}

		return *this;
	}





/***********************************
Przeciazony operator ==
sprawdzamy najpierw, czy stopien obu wielomianow jest rowny.
Jesli jest rozny, to wielomiany napewno nie sa sobie rowne, wiec odrazu mozemy zwrocic false
Jesli stopien jest rowny, to sprawdzamy pokolei ze soba wspolczynniki. Jesli jakis wspolczynnik jest rozny od wspolczynnika
drugiego wielomianu, konczymy petle. Jesli doszlismy do konca petli, oznacza to iz wielomiany sa sobie rowne. Wiec zwracamy true
***********************************/
bool wielomian::operator== (wielomian & argument)
{
	if(stopien!=argument.stopien) { return false;}
	else
	{
		for(int i=0; i<=stopien; i++)
		{
			if((*(wsp+i)) != (*((argument.wsp)+i))) return false;
		}
		return true;
	}
}


/*****************************************
Metoda odpowiedzialna za wprowadzenie przez uzytkownika recznie wszystkich wspolczynnikow wielomianu.
jesli wielomian ma miec inny stopien niz mial wczesniej, nalezy wywolac najpierw metode get_stopien();
*****************************************/
void wielomian::set_wsp()
{
	cout<<"Podaj wspolczynniki wielomianu"<<endl;	
	for(int i=0; i<stopien; i++)
	{
		cout<<"x^"<<stopien-i-1<<":";
		cin>>(*(wsp+i));
		cout<<endl;
	}
}


/*****************************************
Metoda odpowiedzialna zmiane stopnia wielomianu. Zmieniamy atrybut stopien, nastepnie usuwany poprzednia tablice wspolczynnikow,
a nastepnie tworzymy nowa tablice o zadanym rozmiarze, oraz wywolujemy metode losuj_wspolczynniki()
*****************************************/
void wielomian::get_stopien()
{
	cout<<"Podaj nowy stopien wielomianu"<<endl;
	cin>>stopien;
	stopien++;
	delete [] wsp;
	wsp = new float [stopien];
	losuj_wspolczynniki();

}


/******************************************
Przeciazony operator= przypisania
przepisuje stopien, oraz tablice, kopiujac wartosci wspolczynnikow
******************************************/
wielomian wielomian::operator= (wielomian & argument)
	{
		this->stopien=argument.stopien;
		this->wsp = new float [stopien];
		memcpy(wsp, argument.wsp, (stopien*sizeof(float)));
		return *this;
	}

wielomian.h

#include <iostream>
#include <time.h>

using namespace std;


class wielomian
{
public:
	float *wsp;
	int stopien;

	wielomian();
	wielomian(int _stopien);
	wielomian (const wielomian &wzor);
	~wielomian();

	void losuj_wspolczynniki();
	void set_wsp();
	friend ostream & operator<<(ostream &wyjscie, const wielomian & obiekt);
	friend istream & operator>>(istream &wejscie,  wielomian & obiekt);
	wielomian operator+ (wielomian & liczba);
	wielomian operator- (wielomian & liczba);
	bool operator== (wielomian & argument);
	wielomian operator= (wielomian & argument);
	void get_stopien();
};
0

dla równań do 4 stopnia, można stosować wzory. Dla równań powyżej 4 stopnia nie ma wzorów i trzeba stosować metody numeryczne dające przybliżone rozwiązania np. metoda Newtona

0

Miejsca zerowe w danym przedziale można obliczyć w sposób brute-force. Mianowicie:

  1. jedziesz w pętli po x-ach, z zadaną dokładnością np. epsilon = 0.01
  2. obliczasz wartość wielomianu w tym punkcie: W(x), zapisujesz znak tej wartości
  3. obliczasz wartość w następnym punkcie i znowóż sprawdzasz znak
  4. jeśli się zmienił znak, to znaczy że gdzieś "pomiędzy" jest miejsce zerowe, można to uśrednić

Dla przedziału powiedzmy [-10, 10] z dokładnością 0.01 będzie (10 + 10)/0.01 iteracji.

0

Zrób tak:

  1. Jeśli stopień wielomianu jest nie większy niż 4 to zastosuj wzory.
  2. Jeśli wstąpień wielomianu jest większy to stosujesz metodę prób i błędów jak opisał kolega wyżej.
  3. Gdy już znajdziesz co najmniej jedno miejsce zerowe (im więcej tym lepiej) to bierzesz swój wielomian i dzielisz go przez wielomiany typu (x-xi), gdzie xi to kolejne miejsca znalezione przez ciebie. W ten sposób uzyskasz wielomian o stopniu o tyle mniejszym ile miejsc zerowych znalazłeś i jego miejsca zerowe pokrywają się z pozostałymi miejscami zerowymi pierwotnego wielomianu. Od tego momentu zaczynasz proces od początku, do momentu aż punkt pierwszy załatwi sprawę lub nie będziesz w stanie znaleźć miejsc zerowych.

Dodatkowo polecam wizytę w bibliotece i książkę "Numerical Recipies" tam na 100% jest opisany algorytm jak to najlepiej policzyć.

0

Wzory to raczej tylko ciekawostka, nie mają sensu dla stopnia > 2. Narzut niedokladnosci operacji na liczbach zmiennoprzecinkowych powoduje, ze dokladniejsze wyniki osiaga sie metodami przyblizonymi

1 użytkowników online, w tym zalogowanych: 0, gości: 1