Strona główna » Algorytmy » Artykuły » Ułamek z liczby dziesiętnej
 

Ułamek z liczby dziesiętnej

· część 1 · część 2 ·

Wstęp

W poprzedniej części została utworzona klasa ulamek, która umożliwia pracę na ułamkach w trakcie wykonywania programu bez błędu przybliżenia. Klasa choć funkcjonalna wciąż można rozszerzać dodając nowe funkcjonalności.

Idea

Pierwsze rozszerzenie biblioteki będzie dotyczyć rozszerzenia funkcjonalności o wczytywanie ułamka z zapisu dziesiętnego. Przykładowo ułamek będzie można utworzyć wpisując tylko 3,72. Problem ten można rozwiązać mnożąc licznik przez m aż nie będzie części ułamkowej. Później wystarczy ustalić mianownik na m i zredukować ułamek, aby uzyskać najprostszy zapis wczytanej liczby przy pomocy ułamka.

Implementacja

Wczytywanie ułamka z liczby dziesiętnej będzie możliwe podczas tworzenia zmiennej, dlatego zostanie dodany nowy konstruktor, który przyjmował jako argument liczbę rzeczywistą x. Na jej podstawie zostanie utworzony ułamek, który będzie reprezentował x.

C++
C#
  1.   ulamek(double x) {
  2.     int mn = 1;
  3.     while (x * mn - int(x * mn) != 0)
  4.       mn *= 10;
  5.     licznik = x * mn;
  6.     mianownik = mn;
  7.     redukuj();
  8.   }

(2.) Na początek istniej przypuszczenie, że liczba nie ma części dziesiętnej, dlatego zmienna mn przyjmuje wartość 1. (3.) Następnie w pętli jest sprawdzane czy po pomnożeniu liczby x przez mn istnieje jakaś część dziesiętna. Jeśli istnieje to (4.) należy pomnożyć mnożnik mn przez 10. Po zakończeniu pętli (5.) odpowiednio zostaje ustalony licznik oraz (6.) mianownik. (7.) Zapisana liczba może jednak zostać zredukowana do prostszej postaci, dlatego wywołana zostaje funkcja redukuj().

Następnie rozpoczyna się sekcja prywatna klasy. Jest to część hermetyzacji klasy. Ma to za zadanie ograniczyć co może wywołać programista na tej klasie. Pozostawienie niektórych z tych funkcji publicznych mogłoby doprowadzić do nieoczekiwanego przerwania działania programu (poprzez nieprawidłową operację). W prywatnej części są zadeklarowane dwie zmienne typu int, które odpowiadają licznikowi i mianownikowi ułamka.

Przypisanie

Posiadając tego typu konstruktor łatwo przypuścić, że programista w trakcie pisania programu chciałby uniknąć wywoływania konstruktora i użyć tylko operatora przypisania =. Z tego powodu zostanie dodany nowy operator.

C++
C#
  1.   ulamek operator = (const double &x) {
  2.     return ulamek(x);
  3.   }

Wypisywanie ułamka

Do tej pory użycie operatora << wypisywało ułamek w najprostszej możliwej postaci - w formie ułamka niewłaściwego. Jednak taka metoda nie zawsze jest przejrzysta. Tym razem cel polega na poprawieniu funkcji tak, aby wypisywała ułamek w formie mieszanej. Wypisywanie w takiej formie pozwoli uniknąć wypisywania np. 12/1.

C++
C#
  1.   friend ostream& operator << (ostream& out, const ulamek& a) {
  2.     if (int(a.licznik / a.mianownik) != 0) {
  3.       out << int(a.licznik / a.mianownik) << " ";
  4.     }
  5.     if (a.licznik % a.mianownik != 0) {
  6.       out << a.licznik % a.mianownik << "/" << a.mianownik;
  7.     }
  8.     return out;

(1.) Deklaracja użycia operatora pozostaje niezmienna. (2.) Sprawdzenie czy istnieje część całkowita ułamka do wypisania. (3.) Jeśli tak to zostaje ona wypisana i dopisany zostaje znak przerwy. (5.) Teraz należy sprawdzić czy istnieje dalej ułamek do wypisania. Jeśli tak to (6.) należy go wypisać w formie jakiej dotychczas był wypisany cały ułamek. (8.) Na koniec zwracany jest wskaźnik na strumień.

Testowanie funkcji

Deklaracja i przypisanie wartości

Przypisanie wartości zmiennej przechowujące ułamki można zapisać na dwa sposoby. Pierwszy z nich korzysta z operatora przypisania, a drugi z konstruktora. Oba są w pełni poprawne.

C++
C#
  1.   ulamek c1 = 3.72;
  2.   ulamek c2 = ulamek(3.72);

Wypisanie wyników

W celu przetestowania nowej metody wypisywania wystarczy wpisać:

C++
C#
  1.   cout << c1 << endl;