Działania na ułamkach

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

  1. 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 parametrach x i y (typu ulamek), zwracającą wartości typu ulamek. (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

  1. Każda funkcja powinna być zdefiniowana przed pierwszym jej użyciem.
  2. Nie można deklarować funkcji wewnątrz innych funkcji (w szczególności wewnątrz funkcij main()).
  3. Parametry funkcji są to zmienne lokalne i nie mają nić wspólnego z innymi zmiennymi o tej samej nazwie użytymi w programie.
  4. 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:

  1. Znajdujemy Największy Wspólny Dzielnik dla licznika i mianownika.
  2. 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;
}
Poprzedni
Następny