Wstęp
Nie będę opisywał tu działań na ułamkach. Coś założyć muszę i zakładam, że w ułamki Państwo umieją.
Całą uwagę poświęcę funkcjom i realizacji algorytmu.
Realizacja
Struktura danych
Umawiamy się (bo jak tak uważam), że każdy ułamek będzie w komputerze reprezentowany jako
- ułamek (być może niewłaściwy) czyli para dwu liczb
- licznik
- mianownik
- znak będzie przechowywany jako znak licznika
- zakładamy, że mianownik jest zawsze dodatni.
Będzie to zrealizowane jako struktura danych
struct Ulamek{
int l; // „l” od licznik
int m; // „m” od mianownik
};
W powyższym l
i m
to „składowe” struktury.
Dodatkowo użyję polecenia typedef
do zdefiniowania nowego typu danych ulamek
:
typedef struct Ulamek ulamek;
W tym układzie każda zmienna mogąca przechowywać ułamek deklarowana będzie jakoś tak:
ulamek a, b;
Gdy trzeba będzie nadać zmiennej wartość początkową zapiszemy to tak:
ulamek c={1, 2}; // pierwsza liczba to licznik, druga mianownik
Aby użyć w obliczeniach składowej (albo zmienić jej zawartość) używamy operatora .
(kropka), czyli:
a.l = 1;
a.m = 2;
nadaje zmiennej a wartość $\dfrac{1}{2}$.
Aby wydrukować wartość ułamka trzeba napisać jakoś tak:
printf("a = (%d, %d)\n", a.l, a.m);
W efekcie wartość zmiennej a
zostanie wydrukowana jako:
a = (1, 2)
Uwagi
Niestety język C nie pozwala na wykonywanie bezpośrednich działań na strukturach danych poza operacją podstawienia, to znaczy można napisać tak:
a = c;
ale nie można napisać tak
a = b + c;
Aby uzyskać efekt dodawania operację trzeba wykonać na składowych, czyli tak:
a.l = b.l * c.m + c.l * b.m; a.m = b.m * c.m
Zmienne strukturalne mogą, natomiast, być parametrami funkcji oraz zadeklarowanym typem funkcji, czyli możliwe jest coś takiego:
ulamek suma(ulamek x, ulamek y);
czyli polecenie deklarujące funkcję
suma()
o dwu parametrachx
iy
(typuulamek
), zwracającą wartości typuulamek
. (Dodatkowo zwracam uwagę, że powyższy zapis jest tak zwanym prototypem funkcji, czyli deklaracją sposobu wywołania funkcji bez definiowania jej algorytmu działania).
Funkcje
Kilka słów na temat funkcji
- Każda funkcja powinna być zdefiniowana przed pierwszym jej użyciem.
- Nie można deklarować funkcji wewnątrz innych funkcji (w szczególności wewnątrz funkcij
main()
). - Parametry funkcji są to zmienne lokalne i nie mają nić wspólnego z innymi zmiennymi o tej samej nazwie użytymi w programie.
- Nie można założyć, że jakakolwiek zmienna użyta wewnątrz funkcji zachowa swoją wartość do kolejnego wywołania funkcji.
Zadanie
Zadanie do wykonania to napisanie programu realizującego podstawowe operacje arytmetyczne na ułamkach:
- dodawanie,
- odejmowanie,
- mnożenie,
- dzielenie.
Dodatkowo program powinien potrafić wydrukować wynik obliczeń.
Żeby zapewnić przechowywanie danych w jak najprostszej postaci ułamki po wykonaniu każdej operacji powinien być „upraszczany” („skracany”).
W optymistycznym wariancie program powinien potrafić:
- wyprowadzić wartość zmiennej jako wartość dziesiętną
- dokonać konwersji ułamka dziesiętnego do zwykłego.
Algorytmy
Operacje na ułamkach
Pomijam algorytmy wykonywania operacji na ułamkach. Zostały one opisane na wykładzie.
Skracanie (upraszczanie) ułamków.
Algorytm jest bardzo prosty:
- Znajdujemy Największy Wspólny Dzielnik dla licznika i mianownika.
- Jeżeli jest on różny od 1 dzielimy licznik i mianownik przez tę liczbę.
Drukowanie ułamka
W najprostszym wariancie wystarczy coś takiego. Dla ułamka $\dfrac{37}{5}$
7 (3, 5)
czyli 7 całych i 3/5.
Dla ułamka $\dfrac{5}{7}$ może to być (5, 7) (Pomijamy część całkowitą!)
W wersji zaawansowanej powinno to wyglądać tak:
3
7 -
5
oraz
5
-
7
Zamiana ułamka zwykłego na dziesiętny
Zamiana ułamka zwykłego na dziesiętny jest banalna, wystarczy licznik podzielić przez mianownik.
Zamiana ułamka dziesiętnego na zwykły (nieobowiązkowe i dla bardzo ambitnych)
Podpowiedź: Liczby podwójnej precyzji pamiętane są z co najwyżej 16 cyframi dziesiętnymi. Jeżeli znamy Rząd wielkości liczby (wartość 12.12345678901234 jest „rzędu” 10 czyli ma dwie cyfry przed kropką dziesiętną i co najwyżej 14 cyfr po; część całkowita to 13, licznik części ułamkowej to 12345678901234 a mianownik to 10^14^).
Żeby sprawę dodatkowo skomplikować to chcę zwrócić uwagę, że liczby całkowite mogą przyjmować wartości co najwyżej 2 miliardy (z kawałkiem). Ale ograniczając liczbę cyfr znaczących… Można też użyć long int
.
Prototyp program
#include <stdio.h>
/*
* Najpierw muszą pojawić się deklaracje/ definicje funkcji
* Poniżej zaproponuję jedynie niektóre funkcje
* - suma
* - uprosc
* i naszkicuję ich sposób wywołania
* Reszta należy do Państwa
*/
/*
* Najpierw deklaracja typu ulamek
*/
struct Ulamek {
int l;
int m;
};
typedef struct Ulamek ulamek;
/*
* Od tej chwili ulamek jest kolejnym nowym typem
*/
/*
* Funkcja uprosc to funkcja, która dokonuje skrócenia ułamka
*/
ulamek uprosc(ulamek x)
{
ulamek wynik;
// tu powinny być obliczenia
return wynik;
}
ulamek suma(ulamek x, ulamek y)
{
ulamek wynik; // rezultat operacji dodawania zostanie zapisany w zmiennej wynik
// tu powinny być obliczenia
//
return wynik;
// Jeżli korzystamy z funkcji skracania zamiast powyższego można użyć
return uprosc(wynik);
// I zawsze wynik działania będzie OK
}
/*
* Ponizej powinny pojawić się definicje innych funkcji wykonujących operacje arytmetyczne
* różnica, iloczyn, iloraz
*/
/*
* Można też przygotować funkcję drukuj
*/
void drukuj(ulamek x)
{
// to przekształcenia do wydruku
}
/*
* Na koniec funkcja main()
*/
int main(void)
{
ulamek a = {1, 3}; // przykładowa wartość pierwszego ułamka
ulamek b = {-3, 4}; // przykładowa wartość drugiego ułamka
ulamek c; // tu będzie mógł być zapisywany wynik
c = suma(a, b);
drukuj(c);
c = iloczyn(a, b);
drukuj (c);
// i tak dalej
return 0;
}