Przy dodawaniu, odejmowaniu i skracaniu ułamków niezbędna będzie wiedza o wyznaczaniu NWD i NWW. Polecam przeczytać najpierw notatkę.

Dodawanie i odejmowanie ułamków

Rozwiązanie to ma jedną znaczącą wadę - wychodzą bardzo duże liczby. Weźmy dla przykładu :

Przy tak małych liczbach róznica nie jest jeszcze aż tak widoczna, ale nietrudno przekroczyć zakres inta przy większych ułamkach.

Najłatwiej by było rozszerzyć oba ułamki do najmniejszego wspólnego mianownika:

Jak znaleźć wspólny mianownik? Posłużymy się wcześniej poznanym NWW. Wspólny mianownik będzie równy najmniejszej wspólnej wielokrotności obu mianowników, czyli:

Następnie musimy wyznaczyć nową wartość liczników. Dla każdego ułamka należy obliczyć ile razy zwiększył się jego mianownik, a następnie otrzymaną wielkość pomnożyć przez stary licznik:

Wyznaczmy wzór ogólny:

Dodajmy teraz wcześniejszą parę ułamków stosując powyższe równanie:

Skoro dodawanie i odejmowanie mamy za sobą, przejdźmy do mnożenia i dzielenia.


Mnożenie i dzielenie ułamków

Tutaj, jako że nie musimy sprowadzać ułamków do tego samego mianownika, będzie łatwiej.

Przy mnożeniu ułamków, mnożymy wszystkie ich liczniki i mianowniki:

Przy dzieleniu ułamków, mnożymy pierwszy ułamek przez odwrotność drugiego. Dzięki temu mamy pewność, że wynik będzie typu całkowitego (mnożymy dwie liczby całkowite).

Możemy jeszcze skracać ułamki podczas ich mnożenia, ale to zostawiam już dla was :). Podpowiem że przydatne będzie i . Nie powinniście mieć problemu z zaimplementowaniem tego po następnym podpunkcie.


Jako że wiemy już jak wykonywać podstawowe działania na ułamkach, pora na skracanie ich do najprostszej postaci.


Skracanie ułamków

Aby skrócić ułamek do najprostszej postaci, należy wyznaczyć największy wspólny dzielnik jego licznika i mianownika i skrócić go przez tą liczbę:

Skróćmy ułamek z poprzedniego przykładu:

To by było na tyle z teorii. Pora na kod realizujący powyższe operacje w praktyce.


Kod C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
#include <algorithm>
using namespace std;

// W całym programie zakładam, że mianownik nigdy nie będzie równy 0
// Dzięki temu nie musimy tego sprawdzać przy wyliczaniu NWW

// Po wytłumaczenie jak wyliczać NWD i NWW odsyłam do notatki o Algorytmie Euklidesa
// https://sszczep.github.io/Niezbednik-Maturzysty-Informatyka/algorytmy/algorytm-euklidesa-wyznaczanie-nwd-i-nww

int NWD(int a, int b) {
	while(b) swap(a %= b, b);
	
	return a;
}

int NWW(int a, int b) {
	return a * b / NWD(a, b);
}

// Struktura przechowywująca licznik i mianownik oraz metody dotyczące działań na ułamkach
struct Ulamek {
	int a, b;
	
	void dodaj(Ulamek ulamek) {
		// Jeżeli ułamki mają te same mianowniki, wystarczy dodać liczniki
		if(b == ulamek.b) {
			a += ulamek.a;
			return;
		}
		
		// W przeciwnym wypadku liczymy wspólny mianownik i nowe liczniki
		int mianownik = NWW(b, ulamek.b);
		int licznik1 = a * (mianownik / b);
		int licznik2 = ulamek.a * (mianownik / ulamek.b);
		
		a = licznik1 + licznik2;
		b = mianownik;
	}
	
	void odejmij(Ulamek ulamek) {
		// Zmieniamy znak licznika na przeciwny i dodajemy ułamki
		ulamek.a *= -1;
		dodaj(ulamek);
	}
	
	void pomnoz(Ulamek ulamek) {
		// Mnożymy liczniki i mianowniki
		a *= ulamek.a;
		b *= ulamek.b;
	}
	
	void podziel(Ulamek ulamek) {
		// Odwracamy drugi ułamek i mnożymy
		swap(ulamek.a, ulamek.b);
		pomnoz(ulamek);
	}
	
	void skroc() {
		// Wyznaczamy NWD i skracamy ulamek
		int nwd = NWD(a, b);
		a /= nwd;
		b /= nwd;
	}
	
	void info() {
		cout << a << "/" << b;
	}
};

int main() {
	Ulamek ulamek{70, 128};
	cout << "Początkowy ułamek: ";
	ulamek.info();
	
	ulamek.dodaj(Ulamek{30, 64});
	cout << "\n70/128 + 30/64 = ";
	ulamek.info();
	
	ulamek.skroc();
	cout << "\nSkrócony: ";
	ulamek.info();
	
	ulamek.odejmij(Ulamek{17, 64});
	cout << "\n65/64 - 17/64 = ";
	ulamek.info();
	
	ulamek.skroc();
	cout << "\nSkrócony: ";
	ulamek.info();
	
	ulamek.pomnoz(Ulamek{2, 4});
	cout << "\n3/4 * 2/4 = ";
	ulamek.info();
	
	ulamek.skroc();
	cout << "\nSkrócony: ";
	ulamek.info();
	
	ulamek.podziel(Ulamek{3, 8});
	cout << "\n3/8 / 3/8 = ";
	ulamek.info();
	
	ulamek.skroc();
	cout << "\nSkrócony: ";
	ulamek.info();
}

Wyjście programu

Początkowy ułamek: 70/128
70/128 + 30/64 = 130/128
Skrócony: 65/64
65/64 - 17/64 = 48/64
Skrócony: 3/4
3/4 * 2/4 = 6/16
Skrócony: 3/8
3/8 / 3/8 = 24/24
Skrócony: 1/1