Kurs podstawy programowania UMCS, zdjęcie laptopa.

PP – Laboratorium 1

Zadanie 1 – Hello World!

Napisz program w języku C++, wypisujący „Hello World!”.

Rozwiązanie:
//Version 1.0
#include <cstdio>

int main() {
	printf("Hello world!");
	return 0;
}
//Version 2.0
#include <iostream>
using namespace std;

int main() {
    cout << "Hello world!";
    return 0;
}
//Version 3.0
#include <iostream>

int main() {
    std::cout << "Hello world!";
    return 0;
}
Omówienie:

Program w języku C/C++, niezależnie od rozmiaru, jest zbudowany z funkcji i zmiennych/obiektów.

Funkcja zawiera instrukcje określające, jakie operacje procesu obliczeniowego należy wykonać, zmienne zaś przechowują wartości używane podczas tego procesu.

W naszym rozwiązaniu występuje funkcja o nazwie main. Zwykle funkcje możemy nazywać dowolnie, jednakże main jest funkcją o specjalnej nazwie. Każdy program musi zawierać funkcję o takiej nazwie i to od tego miejsca zaczyna się start naszego programu. Oczywiście całego kodu nie pisze się jedynie w funkcji main. Główna funkcja programu, bo tak można ją nazywać, aby wykonać zadanie, wywołuje inne funkcje. Tutaj warto dodać, że część z tych funkcji zaimplementujecie sami (jeszcze w tym semestrze), a inne będą pochodzić z gotowych bibliotek tak, jak printf() w powyższym kodzie.

Innym znanym zapisem dla funkcji main jest:
int main(int argc, char *argv[])
są to argumenty funkcji, czym są argumenty funkcji i do czego służą dowiecie się na kolejnych lekcjach z tego kursu. W każdym razie, pierwszy argument funkcji int argc mówi o ilości argumentów, zaś drugi char *argv[] przechowuje wartości tych argumentów w tablicy. Nazewnictwo to wynika z konwencji języka C/C++, ale te argumenty tak nazywać się nie muszą. Zapis int main(int num_args, char** arg_strings) również jest poprawny.

Oprócz nazwy funkcji, argumentów zawarliśmy także informację o typie zwracanej wartości: int (integer), czyli liczba całkowita. Więcej o funkcjach powiemy sobie w przyszłości. Aktualnie należy pamiętać, że kod funkcji umieszcza się w nawiasach klamrowych { }, a kolejne polecenia rozdzielone są średnikami.


Linia 1 (Version 1.0, 2.0 i 3.0): komentarze.
Czym są komentarze? Jak podają źródła w Internecie:

Komentarz jest to notatka sporządzona przez programistę, 
znajdująca się w kodzie źródłowym programu. 
Komentarz w żaden sposób nie wpływa na działanie programu.

W języku C i C++ mamy do dyspozycji trzy rodzaje komentarzy: jednowierszowy, wielowierszowy i wykonany za pomocą dyrektyw preprocesora.

Dwa ukośniki // służą nam do rozpoczęcia komentarza jednowierszowego i trwa on do miejsca wystąpienia tych znaków do końca wierszu. Oczywiście od powyższej reguł istnieją wyjątki:
printf("To // komentarzem nie będzie.");
Komentarzem nie stanie się tekst zawarty w podwójnych apostrofach.

Komentarz wielowierszowy rozpoczyna się znakami /* i kończy */. Na przykład:
/* jest to komentarz
w wielu liniach */


Generalnie zaleca się stosować komentarze jednowierszowe, gdy dodajemy jakieś opisy działania programu. Komentarz wielowierszowy przydaje się często gdy chcemy wymienić jakiś stary algorytm na nowy, np. wersję źle działającą algorytmu komentujemy i w miejsce starego kodu piszemy nową, jednocześnie mając wgląd na to co wcześniej napisaliśmy.

Wskazówka: Dobry kod komentuje się sam. Wraz ze zwiększaniem wiedzy i umiejętności programistycznych można mieć wrażenie, że komentarze są zbędne. Faktem jest, że programiści z większym doświadczeniem bardzo skromnie komentują kod lub nie robią tego wcale. Wynika to z dobrze napisanego kodu, poprawnie nazwanych zmiennych i funkcji. To nie znaczy, że komentarze nie są potrzebne są momenty, gdy są użyteczne. Wręcz przeciwnie na początku nauki programowania mogą być bardzo użyteczne.


Linia 2 (Version 1.0, 2.0 i 3.0): dyrektywy.
Wszystkie wiersze, które zaczynają się znakiem # nazywamy dyrektywami preprocesora. Każda dyrektywa musi zaczynać się od nowego wiersza.

Linijka druga zleca kompilatorowi dołączenie do programu informacji o standardowej bibliotece wejścia-wyjścia. W języku C++ deklaracje funkcji zawarte są w plikach nagłówkowych. Taki plik dołączamy do naszego programu przy pomocy dyrektywy preprocesora #include.

Version 1.0: Plik cstdio (stdio.h), dołączony za pomocą dyrektywy preprocesora, zawiera niezbędne dla kompilatora opisy funkcji np. prinf. Jest to standardowa biblioteka, która umożliwia pracę z konsolą i plikami.


Linia 3 (Version 2.0): przestrzeń nazw.
Aktualnie nie będę rozbudował tematu przestrzeni nazw. Na ten moment, musicie uwierzyć mi na słowo, ale tak się pisze, jest to potrzebne. Możemy użyć jednokrotnie frazy using namespace std; lub przed każdym odniesieniem się do funkcji lub obiektu z biblioteki użyć frazy std:: np.
std::cout << "1" << std::endl; (Version 3.0)
lub tak, jak pojawiło się to w kodzie using namepsace std; i wtedy std:: pomijamy przy cout.

Za pomocą słów kluczowych using namespace informujemy kompilator, że chcemy aby wszystkie funkcje, klasy i szablony należące do przestrzeni nazw były w głównej przestrzeni i nie wymagały przedrostka. Wyraz występujący po instrukcji using namespace jest istniejącą nazwą przestrzeni. Dla standardowych bibliotek C++ przestrzeń nazwana jest std.


Linia 5 (Version 1.0): wywołanie funkcji.
To wywołanie funkcji printf ze standardowej biblioteki wejścia-wyjścia. Funkcję wywołuje się podając jej nazwę i w nawiasach listę argumentów. Argumentem nazywamy wartości przekazywane do funkcji, kolejne argumenty są rozdzielone przecinkami.
Warto zuważyć i zapamiętać, że na końcu każdej instrukcji (lub grupy instrukcji) musi znaleźć się średnik ;, który informuje kompilator gdzie ta instrukcja się kończy.

Nasza funkcja posiada jeden argument i jest nim "Hello world!". Funkcja ta wypisuje tekst na standardowe wyjście (zazwyczaj ekran monitora i konsola), w tym przypadku ciąg znaków ujęty w znaki cudzysłów. "Hello world!" najczęściej nazywamy stałą napisową (ang. string), bądź po prostu napisem i na razie będziemy stosować je jedynie w argumentach funkcji printf. Należy dodać, że printf może przyjmować więcej niż jeden argument:
printf("%d", 3 + 4)
Tym razem funkcja printf przyjęła dwa argumenty rodzielone przecinkiem: stałą napisową oraz działanie arytmetyczne. Porównując wywołanie funkcji z treścią którą otrzymamy (wyświetlona zostanie liczba 7) można łatwo zauważyć, że zamiast zapisu %d pokaże się nam liczba 7. Znak % w stałej napisowej jest znakiem specjalnym rozpoczynającym sekwencję sterującą, po którym następuje określenie sposobu prezentacji kolejnych argumentów funkcji printf. Zapis %d informuje, że argumentem będzie liczba całkowita. printf jest znacznie bardziej rozbudowana niż ten jeden podstawowy typ. Nie będziemy się jednak w nią zagłębiać ze względu na to, iż będziemy wykorzystywali inne i znacznie prostsze narzędzie do wypisywania danych.


Linia 6 (Version 2.0), Linia 5 (Version 3.0): strumienie.
Pomimo tego, że poznaliśmy właśnie jedną technikę wypisywania różnych danych na ekranie – pora poznać kolejną. Kolejna technika to używanie strumienia wyjściowego cout. Zapis cout (skrót od (C)onsole (OUT)put) powoduje skierowanie danych ze zmiennej na standardowy strumień wyjściowy, którym jest ekran monitora, tak samo, jak robiła to funkcja printf. W tej linii kodu występują również znaki << przy zapisie cout, które nazywamy operatorem. Za pomocą operatora <<wskazujemy’ dane, które mają zostać przekazane do strumienia.
cout << "Hello world!";
cout << 3 + 4;


Można zauważyć istotną różnicę w stosunku do printf, a mianowicie brak %d. Powoduje to, że nie musimy znać typu wyświetlanych danych, a co za tym idzie musimy mniej pamiętać, aby otrzymać ten sam efekt. Tym samym znacznie częściej będziemy korzystali ze strumienia wyjściowego std::cout. Wracając do typów, należy pamiętać, że język C++ oferuje kilkanaście typów podstawowych np. liczba całkowita krótka 16-bitowa, zwykła 32-bitowa i długa 64-bitowa. Każda z wcześniej wymienionych liczb może być ze znakiem lub bez. Do tego dochodzą znaki, liczby zmiennoprzecinkowe, wartości logiczne, wskaźniki i być może jeszcze inne podstawowe typy, które w chwili obecnej pominąłem. Dla każdego wyżej wymienionego typu zapis w funkcji printf występujący po % będzie wyglądał inaczej, natomiast w przypadku użycia mechanizmu C++ kompilator 'wie’ co z danym typem zrobić.


Linia 6 (Version 1.0 i 3.0) i 7 (Version 2.0): zwracanie wartości przez funkcję.
Nasza funkcja main, poza wyświetleniem komunikatu, zawiera tylko jedno polecenie do wykonania: zakończ funkcję z wynikiem 0.
return 0;
Liczba ta będzie zwrócona do systemu operacyjnego jako wynik działania programu.
Zauważ średnik kończący instrukcję.

Zadanie 2 – zmienne i operacje arytmetyczne

Napisz program w języku C++, który stworzy dwie zmienne typu całkowitego, przypisze im dowolne wartości i wyświetli ich sumę.

Rozwiązanie:
//Version 1.0
#include <cstdio>

int main() {
    int a, b, c;
    a = 1;
    b = 2;
    c = a + b;
    printf("%d + %d = %d", a, b, c);
    return 0;
}
//Version 2.0
#include <cstdio>

int main() {
	int a = 1;
	int b = 2;
	printf("%d + %d = %d", a, b, a + b);
	return 0;
}
//Version 3.0
#include <iostream>
using namespace std;

int main() {
    int a = 1, b = 2;
    cout << a << " + " << b << " = " << a + b;
    return 0;
}
Omówienie:

Zmienna jest to pewien fragment pamięci o ustalonym rozmiarze, który posiada własny identyfikator (nazwę) oraz może przechowywać pewną wartość, zależną od typu zmiennej.

Nazwy zmiennych nie mogą zawierać polskich znaków diakrytycznych, a dozwolone znaki to: małe litery ( a...z ), duże litery ( A...Z ), podkreślenie ( _ ) i cyfry ( 0...9 ). Ponadto nazwa zmiennej nie może zaczynać się od liczby, zmienne muszą posiadać unikatowe nazwy w obrębie całego bloku. Należy nadmienić, że zmienna int a; nie jest tą samą zmienną co int A;, są to dwie różne zmienne, o różnych nazwach.

Zasięg zmiennych. Zmienna widoczna jest tylko w obrębie jednego bloku, czyli w obrębie klamry { ... }.


Linia 5 (Version 1.0): definiowanie zmiennych.
Aby móc skorzystać ze zmiennej należy ją przed użyciem zdefiniować, to znaczy poinformować kompilator, jak zmienna będzie się nazywać i jaki typ ma mieć. Zmienne definiuję w następujący sposób:
typ nazwa_zmiennej;


Linie 5-6 (Version 2.0) i 6 (Version 3.0): inicjowanie zmiennych.
Zmiennej w momencie zdefiniowania można od razu przypisać wartość (zainicjować), za pomocą operatora przypisania =. Zmienne definiujemy i inicjalizujemy w następujący sposób:
typ nazwa_zmiennej = wartość;
Należy pamiętać, że jeśli zmiennej nie przypiszemy żadnej wartości będzie miała wartość przypadkową. Kompilator nie zeruje wartości zmiennych! Jeśli chcemy od razu nadać zmiennej początkową wartość, możemy to zrobić korzystając z przedstawionego wyżej zapisu – dokonujemy wówczas inicjalizacji zmiennej początkową wartością.

Wskazówka: Dobrą praktyką programowania jest zdefiniowanie zmiennych na początku bloku, czyli przed pierwszą instrukcją (kiedyś było to wymagane). Jednakże według nowszych standardów, C i C++ umożliwia zdefiniowanie zmiennej w dowolnym miejscu programu, ale wtedy musimy pamiętać, aby zdefiniować zmienną przed jej użyciem.


Operatory w C/C++ pełnią funkcję podobną do tej pełnionej przez operatory w matematyce. Istnieją różne grupy operatorów i umożliwiają one przeprowadzanie różnych działań na zmiennych.

O jednym operatorze już powiedzieliśmy, jest to operator przypisania =. Operator ten ma łączność prawostronną tzn. obliczanie przypisań następuje z prawa na lewo i zwraca on przypisaną wartość, dzięki czemu może być używany kaskadowo:
a = b = c = 3;
Tym samym wszystkim zmiennym a, b i c zostanie przypisana wartość 3.

Istnieją również operatory arytmetyczne ( +, -, /, *, % ), które pojawiły się w powyższym kodzie. Tak jak w matematyce kolejność działań ma znaczenie, tak w programowaniu, w języku C/C++ jest istotna. Szerzej zostanie to omówione na kolejnych zajęciach z tego kursu.

Należy wspomnieć również o skróconym zapisie, który umożliwia C/C++, o postaci a #= b, gdzie # jest jednym z operatorów: +, -, /, *, %, &, |, ^, << lub >>. Część z nich omówimy w kolejnym wpisie z tego kursu. Powyższy zapis jest równoważny zapisowi: a = a # (b);.

Zadanie 3 – systemy liczbowe

Napisz program w języku C++, wyświetlający tą samą liczbę na różne sposoby. Liczbe całkowitą w formatach: całkowitym, ósemkowym, szesnastkowym.

Rozwiązanie:
#include <cstdio>

int main() {
  int dval= 15; 
  printf("decimal %d, octal %o, hexadecimal %x\n", dval, dval, dval);
  return 0;
}

Zadanie 4 – odczytywanie danych.

Napisz program w języku C++, który stworzy dwie zmienne typu całkowitego, przyjmujące wartości wprowadzone przez użytkownika i wyświetli ich sumę.

Rozwiązanie:
//Version 1.0
#include <cstdio>

int main() {
    int a, b;
    scanf("%d", &a);
    scanf("%d", &b);
    printf("%d + %d = %d\n", a, b, a + b);
    return 0;
}
//Version 2.0
#include <cstdio>

int main() {
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d + %d = %d", a, b, a + b);
    return 0;
}
//Version 3.0
#include <iostream>

int main() {
    int a, b;
    std::cin >> a;
    std::cin >> b;
    std::cout << a << " + " << b << " = " << a + b << std::endl;
    return 0;
}
//Version 4.0
#include <iostream>
using namespace std;

int main() {
	int a, b; 				
	cin >> a >> b;
	cout << a << " + " << b << " = " << a + b << endl;
	return 0;
}
Omówienie:

Omówimy sobie dwa sposoby odczytywania danych z konsoli, wprowadzonych przez użytkownika. Jest to podstawowy sposób interakcji użytkownika z naszym programem.

Linie 6-7 (Version 1.0) i 6 (Version 2.0): funkcja scanf.
Funkcja scanf odczytuje dane ze standardowego wejścia i robi to zgodnie z określonym formatem. Format składa się ze zwykłych znaków (innych niż znak %) oraz sekwencji sterujących, zaczynających się od symbolu procent, po którym następuje:

  • opcjonalna gwiazdka,
  • opcjonalna maksymalna szerokość pola,
  • opcjonalne określenie rozmiaru argumentu,
  • określenie formatu.

Funkcja scanf obsługuje mi. następujące formaty:

  • d, i – odczytuje liczbę całkowitą, argument powinien być wskaźnikiem na int,
  • f – odczytuje liczbę rzeczywistą, nieskończoność lub NaN, argument powinien być wskaźnikiem na float.

Zapis dla odczytania liczby całkowitej będzie następujący:
scanf("%d", &nazwa_zmiennej);
scanf w pierwszym argumencie przyjmuje napis formatujący (z dowolną ilością sekwencji sterujących), a w kolejnych zmienne, do których mają zostać wprowadzone wartości. Zmienne muszą być koniecznie poprzedzone znakiem ampersand &. Ilość zmiennych i typ musi odpowiadać ilości i typowi wystąpień sekwencji sterujących w łańcuchu formatującym.

Uzupełniając, dla osób zainteresowanych szczegółami, efektem działania tej funkcji będzie zapisanie wartości wprowadzonej przez użytkownika pod adres pamięci zmiennej nazwa_zmiennej. W związku tym, jak można się domyślić zapis &nazwa_zmiennej pobiera adres zmiennej w pamięci. O tym więcej przy szczegółowym omówieniu wskaźników.


Linie 6-7 (Version 3.0) i 7 (Version 4.0): obsługa strumienia wejściowego.
Dokładnie tak, jak w przypadku printf częściej będziemy korzystali z czegoś bardziej związanego z C++, czyli obsługi strumieni.

Wczytywanie danych do zmiennych odbywa się za pomocą strumienia std::cin(skrót od (C)onsole (IN)put). Aby móc wczytać dane znajdujące się na standardowym wejściu, należy wykorzystać do tego celu operator >>. W powyższy sposób możemy wczytywać wszystkie podstawowe typy danych – poczynając od liczb całkowitych, przechodząc przez liczby rzeczywiste oraz znaki, a kończąc na tekście. Podczas tych zajęć skupimy się tylko i wyłącznie na wczytywaniu liczb całkowitych i rzeczywistych.

Zwróćmy uwagę, że nawiasy ostre przy wczytywaniu danych wskazują w przeciwną stronę, niż przy wypisywaniu danych na wyjście. Ich ustawienie w pewnym sensie wskazuje kierunek przepływu danych.

Skoro nauczyliśmy się już korzystać ze strumienia wejściowego w podstawowym wymiarze, przyjrzyjmy się teraz jego działaniu. Wyobraźmy więc sobie, że początkowo strumień jest pusty. Wysyłamy następnie żądanie: „daj mi liczbę całkowitą do zmiennej liczba (czyli: std::cin>>liczba). Strumień jest pusty, więc nie można z niego pobrać danych, a więc użytkownik musi wprowadzić nowe dane do strumienia. W sytuacji, gdy w strumieniu pojawi się inny typ niż oczekiwany np. przecinek ( , ) zamiast oczekiwanej liczby całkowitej, operacja wczytania zakończy się niepowodzeniem, a flaga błędu zostanie ustawiona.

Warto omówić również białe znaki w kontekście obsługi strumieni. Białymi znakami nazywamy te, które nie mają swojej reprezentacji wizualnej, a istnieją w tekście. Białe znaki to: spacja, tabulacja, znak nowej linii. Gdy używamy strumienia std::cin>>, ewentualne białe znaki poprzedzające dane są pomijane. Tak więc gdyby w buforze strumienia znajdował się biały znak, strumień by go po prostu pominął i przeszedł do kolejnego znaku.


Ważne:

Skoro pojawił się temat ewentualnych błędów, omówmy błędy, które mogą pojawić się w języku C/C++.

  1. BŁĘDY SKŁADNIOWE – np. brak średnika, kropka zamiast średnika, nieprawidłowe użycie nawiasów lub błędy w nazwach funkcji – powodują błędy kompilacji.
  2. BŁĘDY SEMANTYCZNE KRYTYCZNE – dzielenie przez zero liczb całkowitych, np. int , przy liczbach rzeczywistych dostaniemy nieskończoność inf (przyda się w zadaniu 7), bądź inne błędy jak naruszenie pamięci – powodują zakończenie programu z błędem.
  3. BŁĘDY SEMANTYCZNE – ich efektem jest błędne działanie programu, nieprzewidywalne.

Zadanie 5

Napisz program w języku C++, który obliczy i wyświetli pole prostokąta dla dowolnych długości boków a i b.

Rozwiązanie:
#include <iostream>

int main() {
    int a = 5, b = 2;
    std::cout << "Pole prostokąta: " << a * b << std::endl;
    return 0;
}

Zadanie 6

Napisz program w języku C++, który stworzy dwie zmienne typu zmiennoprzecinkowego, przyjmujące wartości wprowadzone przez użytkownika i wyświetli ich iloczyn.

Rozwiązanie:
#include <iostream>
using namespace std;

int main() {
	float a, b; 	
	cin >> a >> b;
	cout << a << " * " << b << " = " << a * b << endl;
	return 0;
}

Zadanie 7

Napisz program w języku C++, który pobierze ze standardowego wejścia 3 liczby całkowite. Wartości powinny być pobrane za pomocą jednej instrukcji. Następnie wyświetli na standardowym wyjściu ich średnią arytmetyczną.

Rozwiązanie:
#include <iostream>

int main() {
	int a, b, c;
	float avg;

	std::cin >> a >> b >> c;
	avg = (a + b + c) / 3.0f;  //UWAGA! Przy dzieleniu całkowitym liczba zostałaby zaokrąglona w dół.
	std::cout << "Śr. arytmetyczna: " << avg << std::endl;
	
	return 0;
}

Zadanie 8

Dwunasty wyraz ciągu arytmetycznego (an), określonego dla n >= 1, jest równy 30, a suma jego dwunastu początkowych wyrazów jest równa 162. Napisz program, który obliczy pierwszy wyraz tego ciągu.

Rozwiązanie:
#include <iostream>
using namespace std;

int main() {
	int a_12 = 30, S_12 = 162, n = 12;
	int a_1 = S_12 * 2 / n - a_12; 
	
	cout << "Pierwszy wyraz ciągu to: " << a_1 << "\n";
		
	return 0;
}

Zadanie 9

Zmień program tak by potrafił obliczyć pierwszy wyraz ciągu dla danych wprowadzonych przez użytkownika tj. wartość K, K-ty wyraz ciągu arytmetycznego, suma K-tych początkowych wyrazów. Wszystkie wartości poza K powinny być zmiennoprzecinkowe.

Rozwiązanie:
#include <iostream>
using namespace std;

int main() {
	int k;
	float a_k, S_k;
	
	cin >> k >> a_k >> S_k;
	cout << "Pierwszy wyraz ciągu to: " << S_k * 2.0 / k - a_k << endl;
	
	return 0;
}

Zadanie 10

Napisz program w języku C++, który wczyta dwie godziny w formacie HH:mm. Następnie wyświetl o ile minut różnią się podane godziny. Użyj co najwyżej trzy zmienne całkowite.

Rozwiązanie:
#include <cstdio>

int main() {
    int HH, mm, tmp;

    scanf("%d:%d", &HH, &mm);
    tmp = mm + HH * 60;
    scanf("%d:%d", &HH, &mm);
    tmp -= mm + HH * 60;
    printf("Różnnica to: %d", tmp);

    return 0;
}

Zadanie 11

Ze zbioru wszystkich liczb naturalnych dwucyfrowych losujemy kolejno dwa razy po jednej liczbie bez zwracania. Oblicz prawdopodobieństwo zdarzenia polegającego na tym, że suma wylosowanych liczb będzie równa 30. Wynik wyświetl w notacji naukowej.

Rozwiązanie:
#include <cstdio>

int main() {
    printf("%e", 10.0f / (90.0f * 89.0f));
    return 0;
}
Omówienie:

10,20 11,19 12,18 13,17 14,16 i symetryczne.

Zadanie 12

Napisz program w języku C++ wypisujący na ekranie napis "\n \t" oraz napis reprezentujący ścieżkę dostępu do przykładowego katalogu linuksowego "/usr/bin/xorg/" oraz windowsowego "C:\Windows\System".

Rozwiązanie:
#include <iostream>

int main() {
    std::cout << "\n \t" << std::endl;
    std::cout << "/usr/bin/xorg/" << std::endl;
    std::cout << "C:\\Windows\\System" << std::endl;
    
    return 0;
}

Zadanie 13

Podczas przesyłu danych za pomocą połączenia sieciowego, dołączane są dodatkowe informacje pozwalające na weryfikację poprawności przesłanych danych. Załóżmy, że do każdego bajtu dodawane są dwa bity kontrolne.

Napisz program w języku C++, który przyjmie ze standardowego wejścia rozmiar pliku w megabajtach oraz przepustowość łącza użytego do transmisji w megabitach na sekundę. Program powinien wyświetlić po ilu sekundach plik zostanie przesłany, przy założeniu wykorzystania pełnej przepustowości.

Rozwiązanie:
#include <iostream>

int main() {
    double file_size_mb, capacity, file_size_bits, file_size_control_bits, transmission_time;
    
    std::cin >> file_size_mb >> capacity;

    file_size_bits = file_size_mb * 8 * 1024 * 1024; // 1 MB = 8 * 1024 * 1024 bity
    file_size_control_bits = file_size_bits * (10.0 / 8.0); // dodajemy 2 bity do każdych 8
    transmission_time = file_size_control_bits / capacity / 1024 / 1024;

    std::cout << "Czas transmisji pliku wynosi: " << transmission_time << " sekund.\n";

    return 0;
}

Zadanie 14

Prawo Amdahla określa przyspieszenie działania równoległej implementacji algorytmu w stosunku do szeregowej (wykonywanej w jednym wątku). Wyraża się wzorem: 1 / ((1 - P) + P/S),gdzie P oznacza udział obliczeń, które mogą być zrównoleglone, a S określa przyspieszenie tych obliczeń – zazwyczaj odpowiada liczbie wątków. Napisz program w języku C++, który przyjmie w sekundach czas wykonania pewnego algorytmu za pomocą jednego wątku, procentową część operacji, które mogą zostać zrównoleglone oraz liczbę wątków, które będą przetwarzać algorytm równolegle. Program powinien wyświetlić liczbę sekund, którą zajmie wykonanie algorytmu równolegle.

Rozwiązanie:
#include <iostream>

int main() {
    double one_thread_time, p, parallel_time;
    int num_threads;

    std::cin >> one_thread_time >> p >> num_threads;

    p /= 100.0;
    parallel_time = one_thread_time * ((1 - p) + p / num_threads); 

    std::cout << "Czas wykonania algorytmu za pomocą " << num_threads << " wątków wynosi:  " << parallel_time << " sekund.\n";

    return 0;
}

Zadanie 15

Zmodyfikuj poprzednie zadanie tak, aby przyjmował czas wykonania algorytmu w formacie hh:mm:ss. W takim samym formacie powinien przyjąć godzinę rozpoczęcia działania Program powinien wyświetlić godzinę zakończenia działania w wariancie równoległym.

Rozwiązanie:
#include <cstdio>

int main() {
    double p;
    unsigned int one_thread_time, hh, mm, ss, num_threads, parallel_time;

    scanf("%2d:%2d:%2d", &hh, &mm, &ss);
    scanf("%lf%d", &p, &num_threads);

    one_thread_time = 3600 * hh + 60 * mm + ss;
    p = p / 100.0;

    parallel_time = one_thread_time * ((1 - p) + p / num_threads);
    hh = parallel_time / 3600;
    mm = (parallel_time % 3600) / 60;
    ss = parallel_time % 60;
    
    printf("Czas wykonania algorytmu za pomocą %d, wątków wynosi: %02d:%02d:%02d.\n", num_threads, hh, mm, ss);

    return 0;
}

Zadanie 16

Współczesne dyski twarde dzielą się na sektory, które są podstawową jednostką wymiany danych. Zazwyczaj sektor ma rozmiar 512 bajtów. Odczytywany i zapisywany na dysku jest zawsze cały sektor. Standardem adresowania tych sektorów jest LBA (ang. logical block addressing). Dane na talerzowych dyskach twardych adresowane są fizycznie za pomocą trzech parametrów, cylindra C, głowicy H (ang. head) i ścieżki T (ang. track). Każdy dysk posiada określoną liczbę głowic na cylinder HPC i liczbę sektorów na ścieżkę SPT. Adres logiczny określa się za pomocą wzoru: A = (C × HPC + H) × SPT + (S − 1). Napisz program w języku C++, który pobierze ze standardowego wejścia wartości: HPC, SPT, C, H i S, a następnie wyświetli adres logiczny za pomocą liczby szesnastkowej.

Rozwiązanie:
#include <iostream>

int main() {
    int HPC, SPT, C, H, S;

    std::cin >> HPC >> SPT >> C >> H >> S;
    std::cout << "Adres logiczny: " << std::hex << (C * HPC + H) * SPT + (S - 1) << std::endl;

    return 0;
}

Zadanie 17

Posiadając informacje z poprzedniego zadania, napisz program w języku C++, który otrzyma ze standardowego wejścia adres logiczny w postaci liczby szesnastkowej oraz dziesiątkowe wartości HPC, SPT. Program powinien wyświetlić wartości C, H, S za pomocą liczb dziesiątkowych.

Rozwiązanie:
#include <iostream>

int main() {
    long long A;
    int HPC, SPT, S, H, C;

    std::cin >> std::hex >> A >> std::dec >> HPC >> SPT;
    std::cout << A << std::endl;

    S = (A % SPT) + 1;
    A /= SPT;
    H = A % HPC;
    C = A / HPC;

    std::cout << "Wartości C, H, S: " << C << ' ' << H << ' ' << S << '\n';

    return 0;
}

Przygotuj się na kolejne laboratorium!

W celu przygotowania się na kolejne zajęcia, spróbuj wykonać poniższe zadania samodzielnie.

Zadanie 1

Napisz program w języku C++, który pobierze ze standardowego wejścia dwie liczby całkowite. Program powinien wyświetlić informację czy są one równe.

Zadanie 2

Napisz program w języku C++, który pobierze ze standardowego wejścia dwie liczby zmiennoprzecinkowe. Program powinien wyświetlić ich iloraz, jeżeli druga liczba jest zerem, należy wyświetlić stosowną informację.

Zadanie 3

Napisz program w języku C++, który pobierze ze standardowego wejścia trzy liczby całkowite: a, b, c. Program powinien wyświetlić informację, czy liczba b, jest większa od a, ale mniejsza od c.

Zadanie 4

Napisz program w języku C++, który pobierze ze standardowego wejścia liczbę całkowitą, a następnie wyświetli czy jest ona podzielna bez reszty przez 6, 3 lub 2.

Zadanie 5

Napisz program w języku C++, który pobierze trzy zmiennoprzecinkowe współczynniki równania kwadratowego i wyświetli rozwiązanie(a) lub informację o braku rozwiązań.

3 comments

  1. Emil Benedykciuk

    Drodzy Państwo,

    jeśli w powyższym poście pojawił się błędy, to prosiłbym o informację w komentarzu. Dodatkowo, jeśli mają Państwo jakieś pytania, zapraszam do udzielania się w tej sekcji.

    Pozdrawiam

    P.S Komentarze pojawią się po zatwierdzeniu ich przeze mnie.

  2. Arek

    Dzień dobry, nie jestem pewnien ale w rozwiązaniach zadań 1-2 w pierwszej linijce #include jest zakończona [;] co sprawia że program nie chce się skompilować. Mogę się mylić ale tak mi się wydaje 🙂

  3. Emil Benedykciuk

    Zgadza się, prawdopodobnie podczas edycji rozwiązań, gdzieś pojawiły się nieprzewidziane znaki. Poprawię, dziękuję za spostrzegawczość.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *