Operatory arytmetyczne i przypisania

Cztery działania, reszta z dzielenia i kilka skrótów, bez których nie obejdzie się żaden program. Poznasz też pułapkę, na którą nabiera się niemal każdy początkujący: dlaczego 7 / 2 daje w C# trzy, a nie trzy i pół.

C# operatory modulo Math 45 min
CEL LEKCJI

Czego się dziś nauczysz

  • Wykonasz cztery działania arytmetyczne na zmiennych
  • Wyjaśnisz, czym różni się dzielenie całkowite od zmiennoprzecinkowego
  • Użyjesz operatora % do sprawdzania podzielności i rozbijania liczb
  • Odróżnisz i++ od ++i i wskażesz, kiedy to ma znaczenie
  • Zapiszesz działanie skrótem += zamiast pełną formą
  • Ustalisz kolejność wykonywania działań w złożonym wyrażeniu
TEORIA

Cztery działania i reszta

Operator to symbol wykonujący działanie. Wartości, na których działa, nazywamy operandami.

Program.cs
int wynik = 15 + 4;
//          ^^   ^ ^
//          |    | └── drugi operand
//          |    └── operator
//          └── pierwszy operand
OperatorNazwaPrzykładWynik
+dodawanie15 + 419
-odejmowanie15 - 411
*mnożenie15 * 460
/dzielenie15 / 43 — uwaga!
%reszta z dzielenia (modulo)15 % 43
Program.cs
int a = 15;
int b = 4;

Console.WriteLine($"{a} + {b} = {a + b}");     // 19
Console.WriteLine($"{a} - {b} = {a - b}");     // 11
Console.WriteLine($"{a} * {b} = {a * b}");     // 60
Console.WriteLine($"{a} / {b} = {a / b}");     // 3
Console.WriteLine($"{a} % {b} = {a % b}");     // 3

Zwróć uwagę na dwie ostatnie linie: 15 / 4 daje 3, a nie 3,75. To nie błąd — to zamierzone zachowanie, które omawiamy w następnej sekcji.

Operatory jednoargumentowe

Program.cs
int liczba = 5;

int dodatnia = +liczba;    //  5  — plus jednoargumentowy, praktycznie nieużywany
int ujemna = -liczba;      // -5  — zmienia znak na przeciwny

Console.WriteLine($"{dodatnia} {ujemna}");   // 5 -5
TEORIA

Dzielenie całkowite i reszta

Najważniejsza zasada tej lekcji

Gdy oba operandy są liczbami całkowitymi, wynik dzielenia też jest liczbą całkowitą. Część ułamkowa jest odrzucana, a nie zaokrąglana.

Program.cs
Console.WriteLine(7 / 2);      // 3     — nie 3,5 i nie 4
Console.WriteLine(9 / 2);      // 4     — nie 4,5
Console.WriteLine(1 / 2);      // 0     — nie 0,5!
Console.WriteLine(-7 / 2);     // -3    — ucięcie w stronę zera

Żeby dostać wynik z częścią ułamkową, wystarczy, żeby choć jedna strona była typu double:

Program.cs
int suma = 7;
int ile = 2;

Console.WriteLine(suma / ile);              // 3     ✗ oba całkowite
Console.WriteLine(7.0 / 2);                 // 3,5   ✓ literał z kropką
Console.WriteLine((double)suma / ile);      // 3,5   ✓ rzutowanie zmiennej
Console.WriteLine(suma / (double)ile);      // 3,5   ✓ obojętne, którą stronę

Rzutowanie musi być przed dzieleniem, nie po

double x = (double)(suma / ile); nie pomoże. Nawias każe najpierw wykonać dzielenie całkowite — wynik 3 — i dopiero tę trójkę zamienić na 3,0. Reszta przepadła, zanim zdążyliśmy cokolwiek rzutować.

Operator % — reszta z dzielenia

Modulo zwraca to, co zostaje po podzieleniu. Wygląda niepozornie, a jest jednym z najczęściej używanych operatorów w praktyce.

Program.cs
Console.WriteLine(17 % 5);     // 2   bo 17 = 3*5 + 2
Console.WriteLine(20 % 5);     // 0   dzieli się bez reszty
Console.WriteLine(3 % 5);      // 3   mniejsza od dzielnika, więc cała jest resztą

Do czego naprawdę służy modulo

ZadanieZapisJak to działa
Czy liczba jest parzysta?liczba % 2 == 0Parzyste dzielą się przez 2 bez reszty.
Czy podzielna przez 3?liczba % 3 == 0Ta sama zasada dla dowolnego dzielnika.
Ostatnia cyfra liczbyliczba % 10Reszta z dzielenia przez 10 to zawsze cyfra jedności.
Cyfra dziesiątekliczba / 10 % 10Najpierw obcinamy jedności, potem bierzemy nową ostatnią cyfrę.
Zawijanie w zakresie(indeks + 1) % dlugoscPo ostatnim elemencie wraca do zera — przydatne przy karuzelach i kolejkach.
Godziny z minutminuty / 60 i minuty % 60Dzielenie daje pełne godziny, reszta — minuty.
Program.cs — rozbicie liczby na cyfry
int liczba = 4738;

int jednosci = liczba % 10;              // 8
int dziesiatki = liczba / 10 % 10;       // 3
int setki = liczba / 100 % 10;           // 7
int tysiace = liczba / 1000 % 10;        // 4

Console.WriteLine($"{tysiace} {setki} {dziesiatki} {jednosci}");   // 4 7 3 8

Dzielenie przez zero

SytuacjaCo się dzieje
liczby całkowite, np. a / b gdy b to 0Program przerywa działanie z błędem DivideByZeroException.
liczby zmiennoprzecinkowe, np. 1.0 / 0.0Program działa dalej, a wynikiem jest (nieskończoność).
0.0 / 0.0Wynikiem jest NaN — „nie-liczba”.

Skąd ta różnica

Typy zmiennoprzecinkowe mają w standardzie zarezerwowane wartości specjalne na nieskończoność i „nie-liczbę”. Typy całkowite ich nie mają, więc nie da się w nich zapisać żadnego sensownego wyniku — stąd błąd.

W praktyce oznacza to, że przed dzieleniem przez zmienną warto sprawdzić, czy nie jest zerem. Jak to zrobić, poznasz w lekcji o instrukcjach warunkowych.

TEORIA

Zwiększanie i zmniejszanie o jeden

Dodanie jedynki do zmiennej zdarza się tak często, że język ma na to osobny skrót.

Program.cs
int licznik = 5;

licznik = licznik + 1;    // sposób pełny
licznik += 1;             // sposób skrócony
licznik++;                // sposób najkrótszy — wszystkie trzy robią to samo

Analogicznie licznik-- odejmuje jeden.

i++ czy ++i?

Oba zwiększają zmienną o jeden. Różnią się tym, co zwracają, gdy użyjesz ich w większym wyrażeniu.

i++ — najpierw użyj

Zwraca starą wartość, a dopiero potem zwiększa zmienną.

++i — najpierw zwiększ

Najpierw zwiększa zmienną, a potem zwraca nową wartość.

Program.cs
int a = 5;
int wynikA = a++;      // wynikA dostaje 5, dopiero potem a staje się 6
Console.WriteLine($"a = {a}, wynikA = {wynikA}");     // a = 6, wynikA = 5

int b = 5;
int wynikB = ++b;      // b staje się 6, wynikB dostaje 6
Console.WriteLine($"b = {b}, wynikB = {wynikB}");     // b = 6, wynikB = 6
wynik w konsoli
a = 6, wynikA = 5
b = 6, wynikB = 6

W praktyce ta różnica prawie nigdy nie ma znaczenia

Jeśli piszesz licznik++; jako osobną instrukcję — a tak jest w 99% przypadków — obie wersje zachowują się identycznie, bo nikt nie korzysta ze zwróconej wartości.

Różnica pojawia się dopiero wtedy, gdy wciśniesz ++ w środek większego wyrażenia. Nie rób tego. Zapis tablica[i++] = i++ * 2; jest legalny, ale nieczytelny i niemal zawsze oznacza błąd w projekcie kodu. Rozbij taki kod na osobne linie.

TEORIA

Przypisania złożone

Wzorzec „weź zmienną, coś z nią zrób, wynik włóż z powrotem” jest tak częsty, że dla każdego działania istnieje skrót.

SkrótZnaczy dokładnie to samo coPrzykład
x += 5x = x + 5dopisanie do sumy
x -= 5x = x - 5odjęcie od stanu konta
x *= 2x = x * 2podwojenie
x /= 4x = x / 4podzielenie
x %= 3x = x % 3zostawienie samej reszty
Program.cs
int liczba = 10;

liczba += 5;    // 15
liczba -= 3;    // 12
liczba *= 2;    // 24
liczba /= 4;    // 6
liczba %= 4;    // 2

Console.WriteLine(liczba);     // 2

// Działa też dla tekstu
string zdanie = "Ala";
zdanie += " ma kota";
Console.WriteLine(zdanie);     // Ala ma kota

Drobna różnica, o której warto wiedzieć

Skróty złożone wykonują rzutowanie automatycznie. Zapis bajt += 1; zadziała, a rozpisany bajt = bajt + 1; — nie, bo dodawanie daje wynik typu int, którego nie da się bez pytania wcisnąć z powrotem do byte. Wracaliśmy do tego w lekcji 06.

TEORIA

Kolejność wykonywania działań

C# stosuje te same reguły co matematyka: najpierw nawiasy, potem mnożenie i dzielenie, na końcu dodawanie i odejmowanie.

KolejnośćOperatoryUwaga
1 — pierwsze( )nawiasy wyprzedzają wszystko
2++ -- - (jednoargumentowy)działają na jednej wartości
3* / %modulo ma taki sam priorytet jak mnożenie
4+ -
5 — ostatnie= += -=przypisanie wykonuje się na samym końcu
Program.cs
Console.WriteLine(2 + 3 * 4);        // 14   bo 3*4 policzy się pierwsze
Console.WriteLine((2 + 3) * 4);      // 20   nawias zmienia kolejność
Console.WriteLine(10 - 4 - 3);       // 3    od lewej: (10-4)-3
Console.WriteLine(20 / 4 * 2);       // 10   od lewej: (20/4)*2, nie 20/(4*2)
Console.WriteLine(10 + 6 % 4);       // 12   bo 6%4 wykonuje się przed dodawaniem

Nawias nic nie kosztuje

Nie musisz uczyć się całej tabeli na pamięć. Gdy masz wątpliwość, postaw nawiasy — program będzie działał tak samo szybko, a kod stanie się jednoznaczny dla każdego, kto go przeczyta.

double srednia = (a + b + c) / 3.0; czyta się lepiej niż wersja bez nawiasów, nawet gdyby dawała ten sam wynik.

TEORIA

Operator + dla tekstu

Ten sam znak plus, użyty na napisach, skleja je ze sobą. Nazywamy to konkatenacją.

Program.cs
string imie = "Anna";
string nazwisko = "Kowalska";

string pelne = imie + " " + nazwisko;
Console.WriteLine(pelne);                    // Anna Kowalska

// Można sklejać tekst z liczbą — liczba sama zamieni się na tekst
int wiek = 17;
Console.WriteLine("Wiek: " + wiek);          // Wiek: 17

Klasyczna pułapka: kiedy plus dodaje, a kiedy skleja

Decyduje typ operandów i kolejność od lewej do prawej:

Program.cs
Console.WriteLine("Suma: " + 2 + 3);        // Suma: 23   ✗ nie 5!
Console.WriteLine("Suma: " + (2 + 3));      // Suma: 5    ✓ nawias ratuje
Console.WriteLine(2 + 3 + " to suma");      // 5 to suma  ✓ tu liczby są pierwsze

W pierwszej linii C# najpierw skleja "Suma: " z liczbą 2, dostaje tekst "Suma: 2", a potem dokleja do niego 3. W trzeciej linii kolejność jest odwrotna: najpierw dodaje 2 i 3, bo obie są liczbami, i dopiero wynik skleja z tekstem.

Interpolacja rozwiązuje ten problem raz na zawsze

Zamiast żonglować nawiasami, używaj zapisu ze znakiem $. Wewnątrz klamer wyrażenie liczy się normalnie, a dopiero wynik trafia do tekstu:

Console.WriteLine($"Suma: {2 + 3}");Suma: 5

Dlatego w tym kursie prawie zawsze używamy interpolacji, a sklejania plusem tylko wtedy, gdy naprawdę łączymy dwa napisy.

METODY WBUDOWANE

Klasa Math — gotowe działania

Pierwiastek, potęga i zaokrąglanie nie mają własnych operatorów. Zamiast nich używa się metod z klasy Math. Jest ona statyczna, więc nie tworzy się jej obiektu — wywołujemy metody przez nazwę klasy.

MetodaZwracaCo robi
Math.Abs(x)ten sam typWartość bezwzględna — usuwa znak minus. Math.Abs(-7)7.
Math.Pow(x, y)doublePodnosi x do potęgi y. Math.Pow(2, 10)1024.
Math.Sqrt(x)doublePierwiastek kwadratowy. Math.Sqrt(25)5. Dla liczby ujemnej zwraca NaN.
Math.Round(x, n)doubleZaokrągla do n miejsc po przecinku. Bez drugiego argumentu — do liczby całkowitej.
Math.Floor(x)doubleZaokrągla w dół: Math.Floor(4.9)4.
Math.Ceiling(x)doubleZaokrągla w górę: Math.Ceiling(4.1)5.
Math.Max(a, b)ten sam typWiększa z dwóch liczb.
Math.Min(a, b)ten sam typMniejsza z dwóch liczb.
Math.PIdoubleStała π ≈ 3,14159265358979. To pole, nie metoda — bez nawiasów.
Program.cs
double promien = 3.0;

double pole = Math.PI * promien * promien;
double obwod = 2 * Math.PI * promien;

Console.WriteLine($"Pole:  {Math.Round(pole, 2)}");     // 28,27
Console.WriteLine($"Obwod: {Math.Round(obwod, 2)}");    // 18,85

Console.WriteLine(Math.Pow(2, 10));       // 1024
Console.WriteLine(Math.Sqrt(144));        // 12
Console.WriteLine(Math.Abs(-15));         // 15
Console.WriteLine(Math.Max(7, 12));       // 12

Uwaga na Math.Pow przy liczbach całkowitych

Math.Pow zawsze zwraca double, nawet dla Math.Pow(5, 3). Rzutowanie wyniku na int bywa zawodne, bo obliczenia zmiennoprzecinkowe mogą dać 124,99999999999999 zamiast równych 125 — a rzutowanie ucina część ułamkową, dając 124.

Gdy potęgujesz liczby całkowite i zależy ci na dokładnym wyniku, bezpieczniej użyć (int)Math.Round(Math.Pow(5, 3)) albo po prostu pomnożyć liczbę przez siebie.

PRZYKŁAD Z OMÓWIENIEM

Kasa samoobsługowa — wydawanie reszty

Klient płaci banknotem za zakupy. Program ma policzyć resztę i rozmienić ją na jak najmniejszą liczbę nominałów. To klasyczne zastosowanie pary / i %.

Program.cs
// Wszystko liczymy w groszach, żeby uniknąć ułamków
int doZaplatyGrosze = 4737;      // 47,37 zl
int wplataGrosze = 10000;        // 100,00 zl

int resztaGrosze = wplataGrosze - doZaplatyGrosze;

Console.WriteLine($"Do zaplaty: {doZaplatyGrosze / 100},{doZaplatyGrosze % 100:D2} zl");
Console.WriteLine($"Wplata:     {wplataGrosze / 100},{wplataGrosze % 100:D2} zl");
Console.WriteLine($"Reszta:     {resztaGrosze / 100},{resztaGrosze % 100:D2} zl");
Console.WriteLine();

// Rozmieniamy resztę na nominały — od największego do najmniejszego
int pozostalo = resztaGrosze;

int banknoty50 = pozostalo / 5000;   pozostalo %= 5000;
int banknoty20 = pozostalo / 2000;   pozostalo %= 2000;
int banknoty10 = pozostalo / 1000;   pozostalo %= 1000;
int monety5    = pozostalo / 500;    pozostalo %= 500;
int monety2    = pozostalo / 200;    pozostalo %= 200;
int monety1    = pozostalo / 100;    pozostalo %= 100;
int grosze     = pozostalo;

Console.WriteLine("Wydac:");
Console.WriteLine($"  50 zl  x {banknoty50}");
Console.WriteLine($"  20 zl  x {banknoty20}");
Console.WriteLine($"  10 zl  x {banknoty10}");
Console.WriteLine($"   5 zl  x {monety5}");
Console.WriteLine($"   2 zl  x {monety2}");
Console.WriteLine($"   1 zl  x {monety1}");
Console.WriteLine($"  gr     x {grosze}");
wynik w konsoli
Do zaplaty: 47,37 zl
Wplata:     100,00 zl
Reszta:     52,63 zl

Wydac:
  50 zl  x 1
  20 zl  x 0
  10 zl  x 0
   5 zl  x 0
   2 zl  x 1
   1 zl  x 0
  gr     x 63

Omówienie

FragmentDlaczego tak
Liczenie w groszach Zamiast 47.37 trzymamy 4737. Dzięki temu wszystkie działania są na liczbach całkowitych i nie ma mowy o zgubionym groszu. To standardowa sztuczka w systemach kasowych i bankowych.
resztaGrosze / 100 Dzielenie całkowite daje pełne złotówki — tu właśnie chcemy ucięcia części ułamkowej.
resztaGrosze % 100 Reszta z dzielenia przez 100 to grosze. Razem z poprzednim daje pełną kwotę.
:D2 Format wymuszający dwie cyfry z zerem wiodącym. Bez niego 3 grosze wypisałyby się jako 52,3 zamiast 52,03.
pozostalo %= 5000; Po odliczeniu banknotów pięćdziesięciozłotowych zostawiamy tylko resztę. Kolejny nominał pracuje już na tym, co zostało.
Kolejność nominałów Idziemy od największego do najmniejszego. Odwrotna kolejność dałaby poprawną kwotę, ale wydaną w samych groszach.
CZĘSTE BŁĘDY

Na co uważać

KodProblem
double s = suma / ile; Oba operandy całkowite — reszta przepada przed przypisaniem. Trzeba rzutować jeden z nich: (double)suma / ile.
double s = (double)(suma / ile); Rzutowanie po nawiasie, czyli za późno. Dzielenie już się wykonało całkowicie.
"Suma: " + 2 + 3 Da Suma: 23. Potrzebny nawias albo, lepiej, interpolacja.
x = x++; Wygląda niewinnie, a nie zmienia wartości x. Przypisanie nadpisuje wynik zwiększenia starą wartością. Wystarczy x++;.
int i = 10 / 0; Dzielenie przez stałe zero to błąd kompilacji CS0020, a nie wyjątek. Przy zmiennej byłby wyjątek w czasie działania.
int p = Math.Pow(2, 3); CS0266Math.Pow zwraca double. Potrzebne rzutowanie.
Math.PI() PI to pole, nie metoda. Bez nawiasów.
int x = 5; x =+ 3; Odwrócone znaki. To nie jest +=, tylko przypisanie liczby +3x będzie miało 3, a nie 8. Kompilator nie zgłosi błędu.
ZADANIA

Zadania

ZAD 1Przewidz wynik★☆☆

Zapisz na kartce wynik każdej linii, a dopiero potem uruchom program.

co wypisze?
Console.WriteLine(10 / 3);
Console.WriteLine(10 % 3);
Console.WriteLine(10.0 / 3);
Console.WriteLine(2 + 3 * 4 - 1);
Console.WriteLine((2 + 3) * (4 - 1));
Console.WriteLine("Wynik: " + 5 + 5);
Console.WriteLine(100 % 10 % 3);
pokaż rozwiązanie
3
1
3,3333333333333335
13
15
Wynik: 55
0

Linia 310.0 ma kropkę, więc jest typu double i całe dzielenie liczy się dokładnie. Ogon cyfr to znany nam już efekt zapisu dwójkowego.

Linia 4 — mnożenie przed dodawaniem: 2 + 12 − 1 = 13.

Linia 6 — tekst plus 5 daje "Wynik: 5", a potem dokleja się drugą piątkę.

Linia 7 — od lewej: 100 % 10 to 0, a 0 % 3 to nadal 0.

ZAD 2Sekundy na czas★★☆

Mając liczbę sekund (np. 9876), wypisz ją w formacie godz:min:sek z zerami wiodącymi. Użyj wyłącznie operatorów / i %.

pokaż rozwiązanie
int sekundyRazem = 9876;

int godziny = sekundyRazem / 3600;
int minuty = sekundyRazem % 3600 / 60;
int sekundy = sekundyRazem % 60;

Console.WriteLine($"{godziny:D2}:{minuty:D2}:{sekundy:D2}");
02:44:36

Godzina ma 3600 sekund, więc dzielenie całkowite daje pełne godziny: 9876 / 3600 = 2.

Dla minut najpierw usuwamy pełne godziny (% 3600 zostawia 2676), a potem dzielimy przez 60 — wychodzi 44.

Sekundy to po prostu reszta z dzielenia przez 60. Nie trzeba wcześniej nic odejmować, bo % 60 i tak pomija wszystkie pełne minuty.

Format D2 dopisuje zero wiodące, dzięki czemu widzimy 02 zamiast 2.

ZAD 3Suma cyfr★★☆

Dla liczby czterocyfrowej (np. 4738) oblicz sumę jej cyfr oraz iloczyn. Nie używaj pętli ani konwersji na tekst — same operatory.

pokaż rozwiązanie
int liczba = 4738;

int c1 = liczba / 1000;          // 4  tysiace
int c2 = liczba / 100 % 10;      // 7  setki
int c3 = liczba / 10 % 10;       // 3  dziesiatki
int c4 = liczba % 10;            // 8  jednosci

int suma = c1 + c2 + c3 + c4;
int iloczyn = c1 * c2 * c3 * c4;

Console.WriteLine($"Cyfry:   {c1} {c2} {c3} {c4}");
Console.WriteLine($"Suma:    {suma}");
Console.WriteLine($"Iloczyn: {iloczyn}");
Cyfry:   4 7 3 8
Suma:    22
Iloczyn: 672

Schemat jest zawsze ten sam: dzielenie odcina cyfry z prawej, modulo wybiera ostatnią z tego, co zostało. Przy pierwszej cyfrze % 10 jest zbędne, bo po dzieleniu przez 1000 została już tylko jedna cyfra.

Po lekcji o pętlach wrócisz do tego zadania i napiszesz wersję działającą dla liczby o dowolnej długości.

ZAD 4Kalkulator geometrii★★☆

Dla prostokąta o bokach 7,5 i 3,2 oblicz pole, obwód i długość przekątnej. Wyniki zaokrąglij do dwóch miejsc po przecinku.

pokaż rozwiązanie
double a = 7.5;
double b = 3.2;

double pole = a * b;
double obwod = 2 * (a + b);
double przekatna = Math.Sqrt(a * a + b * b);

Console.WriteLine($"Pole:      {pole:F2}");
Console.WriteLine($"Obwod:     {obwod:F2}");
Console.WriteLine($"Przekatna: {przekatna:F2}");
Pole:      24,00
Obwod:     21,40
Przekatna: 8,15

Przekątną liczymy z twierdzenia Pitagorasa. Zapis a * a jest tu lepszy niż Math.Pow(a, 2) — krótszy, szybszy i bez ryzyka niedokładności.

Zwróć uwagę na nawias w obwodzie. Bez niego 2 * a + b policzyłoby coś zupełnie innego.

ZAD 5Znajdź cztery błędy★★★

Program ma policzyć średnią z trzech ocen i pole koła. Nie działa poprawnie — znajdź i popraw cztery usterki. Uwaga: nie wszystkie z nich zatrzymają kompilację.

do poprawienia
int ocena1 = 5, ocena2 = 4, ocena3 = 4;
double srednia = ocena1 + ocena2 + ocena3 / 3;
Console.WriteLine("Srednia: " + srednia);

double promien = 2.5;
int poleKola = Math.PI * promien * promien;
Console.WriteLine("Pole: " + poleKola);
pokaż rozwiązanie
int ocena1 = 5, ocena2 = 4, ocena3 = 4;
double srednia = (ocena1 + ocena2 + ocena3) / 3.0;   // 1. nawias  2. dzielenie przez 3.0
Console.WriteLine($"Srednia: {srednia:F2}");

double promien = 2.5;
double poleKola = Math.PI * promien * promien;       // 3. double, nie int
Console.WriteLine($"Pole: {poleKola:F2}");           // 4. interpolacja + zaokrąglenie
Srednia: 4,33
Pole: 19,63

Błąd 1 — brak nawiasu. Dzielenie ma wyższy priorytet niż dodawanie, więc oryginalny kod liczył 5 + 4 + (4 / 3), czyli 5 + 4 + 1 = 10. Program się kompilował i wypisywał bzdurę — to najgroźniejszy rodzaj błędu.

Błąd 2 — dzielenie całkowite. Nawet z nawiasem 13 / 3 dałoby 4 zamiast 4,33. Trzeba dzielić przez 3.0.

Błąd 3 — zły typ. Math.PI to double, więc całe wyrażenie jest typu double i nie zmieści się w int. To jedyny błąd, który zatrzyma kompilację (CS0266).

Błąd 4 — brak zaokrąglenia. Bez formatu F2 zobaczylibyśmy 19,634954084936208. Przy okazji zamieniamy sklejanie plusem na interpolację.

ZAD 6Zamiana bez trzeciej zmiennej★★★

W lekcji 04 zamieniałeś wartości dwóch zmiennych, używając trzeciej pomocniczej. Zrób to teraz bez niej, korzystając wyłącznie z dodawania i odejmowania.

pokaż rozwiązanie
int a = 5;
int b = 9;

Console.WriteLine($"Przed: a = {a}, b = {b}");

a = a + b;    // a = 14  (mamy w a sume obu liczb)
b = a - b;    // b = 14 - 9 = 5   (czyli stare a)
a = a - b;    // a = 14 - 5 = 9   (czyli stare b)

Console.WriteLine($"Po:    a = {a}, b = {b}");
Przed: a = 5, b = 9
Po:    a = 9, b = 5

Sztuczka polega na tym, że po pierwszej linii zmienna a przechowuje sumę obu liczb. Odejmując od niej jedną, dostajemy drugą.

Ale nie używaj tego w prawdziwym kodzie. Wersja z trzecią zmienną jest czytelniejsza, a ta może się przepełnić, gdy suma przekroczy zakres typu. To ciekawostka pokazująca, że ten sam efekt da się osiągnąć różnymi drogami — nie zalecana praktyka.

PODSUMOWANIE

Co trzeba zapamiętać

  • Dzielenie dwóch liczb całkowitych daje liczbę całkowitą — reszta jest odrzucana, nie zaokrąglana.
  • Żeby dostać ułamek, rzutuj jedną stronę na doubleprzed dzieleniem, nie po.
  • % zwraca resztę. Służy do sprawdzania podzielności, wyciągania cyfr i zawijania indeksów.
  • Dzielenie całkowite przez zero przerywa program; zmiennoprzecinkowe daje nieskończoność.
  • i++ zwraca starą wartość, ++i nową. Jako osobna instrukcja są nierozróżnialne — i tak należy ich używać.
  • x += 5 to skrót od x = x + 5. Działa też dla tekstu.
  • Kolejność jak w matematyce: nawiasy, potem * / %, na końcu + -. W razie wątpliwości postaw nawias.
  • Plus przy tekście skleja. "Suma: " + 2 + 3 da Suma: 23 — używaj interpolacji.
  • Pierwiastek, potęga i zaokrąglanie to metody klasy Math. Math.PI jest polem, więc bez nawiasów.