Pomoce:

Instalacja Code Blocks i tworzenie projektu aplikacji konsoli.
Struktura programu w języku C++
Zmienne i strumienie w języku C++

 

Instrukcja warunkowa w języku C++

Instrukcja warunkowa (ang. conditional statement) pozwala wykonywać pewne instrukcje przy spełnionym bądź nie spełnionym warunku (ang. condition) - dzięki niej program nie musi zawsze biegnąć tą samą ścieżką, lecz w zależności od zastanej sytuacji może on wybierać właściwą drogę. Bez instrukcji warunkowej komputery byłyby niczym więcej niż kalkulatorami. Dzięki niej mogą rozwiązywać dowolnie skomplikowane problemy. Instrukcja warunkowa posiada w języku C++ następującą składnię:

 

if(warunek) instrukcja1; else instrukcja2;

 

warunek jest wyrażeniem logicznym, które może przyjmować wartość false albo true. W zależności od jego wartości wykonywana jest jedna z instrukcji:

warunek = true - wykonywana jest instrukcja1, a instrukcja2 zostaje pominięta
warunek = false - pominięta zostanie instrukcja1, a wykonana instrukcja2.

 

Jeśli warunkowo wykonujemy tylko jedną instrukcję, to człon z else można pominąć:

 

if(warunek) instrukcja;

 

Teraz instrukcja będzie wykonana, jeśli warunek jest prawdziwy. Jeśli jest on fałszywy, to program pominie instrukcję i przejdzie do dalszej swej części.

 

Jeśli w ramach instrukcji warunkowej chcemy wykonywać więcej niż jedną instrukcję, to stosujemy tzw. instrukcję złożoną, czyli dowolnie dużą grupę instrukcji ujętych w klamerki:

 

if(warunek)
{
  ciąg instrukcji wykonywanych, gdy warunek jest prawdziwy
}
else
{
  ciąg instrukcji wykonywanych, gdy warunek jest fałszywy
}

 

Zwróć uwagę, że po klamerkach obejmujących grupę instrukcji nie stosujemy już średnika.

 

warunek może być również wyrażeniem arytmetycznym. W takim przypadku wartość zero jest traktowana jak false, a wartość różna od zera jest traktowana jak true - niekiedy to podejście upraszcza zapis programu.

 

W warunkach można stosować operatory porównań - wynikiem działania takiego operatora jest true, jeśli relacja jest spełniona i false w przypadku jej niespełnienia. Mamy następujące operatory porównań (a i b to wyrażenia arytmetyczne, niekoniecznie zmienne!):

 

Operator Przykład
== a == b
!= a != b
< a < b
<= a <= b
> a > b
>= a >= b

 

Należy uważać z operatorem równości ==, gdyż pominięcie jednego znaku = robi z niego instrukcję przypisania:

 

if(a == 10) b = 0// zeruje zmienną b tylko wtedy, gdy zmienna a jest równa dziesięć.

if(a = 10b = 0// zmienna b będzie zawsze zerowana, dodatkowo zmienna a przyjmie wartość 10

W drugiej wersji zamiast warunku porównania a == 10 mamy zwykłe przypisanie a = 10. Instrukcja przypisania posiada wartość równą przypisywanemu wyrażeniu - w tym przypadku 10. Ponieważ jest to wartość różna od zera, to instrukcja if zinterpretuje ją jako true i wykona przypisanie b = 0. Widzimy zatem, że bez względu na wartość zmiennej a, przypisanie b = 0 będzie wykonywane zawsze. Dodatkowo zawartość zmiennej a zostanie stracona i zastąpiona liczbą 10 - a o to przecież nam nie chodziło.

 

// Znajdowanie większej z dwóch liczb
// (C)2010 I LO w Tarnowie
//-----------------------------------

#include <iostream>

using namespace std;

int main()
{
    int a,b;

    cin >> a >> b;
    if(a > b) cout << a;
    else      cout << b;
    cout << endl;    

    return 0;
}

 

// Obliczanie wartości bezwzględnej
// (C)2010 I LO w Tarnowie
//---------------------------------

#include <iostream>

using namespace std;

int main()
{
    int a;

    cin >> a;
    if(a < 0) a = -a;
    cout << a << endl;    

    return 0;
}

 

// Porządkowanie dwóch liczb
// (C)2010 I LO w Tarnowie
//--------------------------

#include <iostream>

using namespace std;

int main()
{
    int a,b,x;

    cin >> a >> b;
    if(a > b)
    {
      x = a; a = b; b = x;
    }
    cout << a << " " << b << endl;    

    return 0;
}

 

// Badanie znaku liczby
// (C)2010 I LO w Tarnowie
//------------------------

#include <iostream>

using namespace std;

int main()
{
    int a;

    cin >> a;
    if(a > 0)        cout << "DODATNIA\n";
    else if (a == 0) cout << "ZERO\n";
         else        cout << "UJEMNA\n";
    return 0;
}

 

// Wyszukiwanie największej liczby z trzech
// (C)2010 I LO w Tarnowie
//-----------------------------------------

#include <iostream>

using namespace std;

int main()
{
    int a,b,c,x;

    cin >> a >> b >> c;
    x = a;
    if(b > x) x = b;
    if(c > x) x = c;
    cout << x << endl;
    
    return 0;
}

 

Funkcje logiczne

W języku C++ nad wyrażeniami możemy przeprowadzać operacje logiczne. Mamy trzy podstawowe funkcje logiczne:

NEGACJA !
a !a
false true
true false
ALTERNATYWA ||
a b a || b
false false false
false true true
true false true
true true true
KONIUNKCJA &&
a b a && b
false false false
false true false
true false false
true true true

 

Wynikiem negacji (zaprzeczenia logicznego) jest zawsze wartość logiczna przeciwna do wartości argumentu.
Wynik alternatywy (suma logiczna) jest fałszem, jeśli wszystkie argumenty posiadają wartość logiczną false, a w przeciwnym razie wynik jest prawdą.
Wynik koniunkcji (iloczynu logicznego) jest prawdą tylko wtedy, gdy wszystkie argumenty maja wartość logiczną true, inaczej jest fałszem.

Jeśli wyrażenie a lub b jest wyrażeniem arytmetycznym, to wartość równa zero jest traktowana jak false, a wartość różna od zera jako true. Wynik funkcji logicznej jest zawsze wartością logiczną true lub false.

 

// Sprawdzanie przynależności liczby c
// do przedziału zamkniętego <a,b>
// (C)2010 I LO w Tarnowie
//------------------------------------

#include <iostream>

using namespace std;

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

    cin >> a >> b >> c;
    if(a <= c && c <= b) cout << "TAK\n";
    else                 cout << "NIE\n";
    
    return 0;
}

 

// Sprawdzanie podzielności przez 2 lub 3
// (C)2010 I LO w Tarnowie
//---------------------------------------

#include <iostream>

using namespace std;

int main()
{
    int a;

    cin >> a;
    if(a % 2 == 0 || a % 3 == 0) cout << "TAK\n";
    else                         cout << "NIE\n";
    
    return 0;
}

 

Wykorzystując wyrażenia arytmetyczne i funkcję negacji powyższy program można zapisać nieco krócej (czy potrafisz powiedzieć jak to działa?):

 

// Sprawdzanie podzielności przez 2 lub 3
// (C)2010 I LO w Tarnowie
//---------------------------------------

#include <iostream>

using namespace std;

int main()
{
    int a;

    cin >> a;
    if(!(a % 2) || !(a % 3)) cout << "TAK\n";
    else                     cout << "NIE\n";
    
    return 0;
}

 

Porównania liczb zmiennoprzecinkowych

Przy pracy z typem double musimy zdawać sobie sprawę, że liczba zmiennoprzecinkowa jest liczbą przybliżoną (posiada precyzję 15 cyfr znaczących). Zatem rachunki wykorzystujące ten typ danych są rachunkami przybliżonymi i zwykle obarczone zostają pewnym (bardzo małym, ale zawsze) błędem. Uruchom poniższy program:

 

// Porównywanie liczb double
// (C)2010 I LO w Tarnowie
//--------------------------

#include <iostream>

using namespace std;

int main()
{
    double x;

    x = 0.1;
    if(x * 10 == 1) cout << "JEST OK\n";
    else            cout << "JEST NIEDOBRZE\n";
    
    return 0;
}

 

Co robi ten program? Otóż wpisuje do zmiennej x wartość 1/10, a następnie sprawdza, czy 10 * x jest równe 1. Jeśli tak, to powinniśmy otrzymać napis JEST OK. Tymczasem otrzymujemy napis JEST NIEDOBRZE. Dlaczego? Przecież skoro x zawiera wartość 1/10, to pomnożone przez 10 powinno dać wynik 1! Otóż nie, nie daje 1, gdyż wyraźnie warunek jest niespełniony. Co zatem się dzieje w  tak prostym programie, że wynik jest błędny?

Winowajcą jest wartość 1/10, która w systemie dwójkowym tworzy ułamek nieskończony - tak jak np. w systemie dziesiętnym ułamek 1/3 jest nieskończony - 0,33333... Komputer zapamiętuje liczby z określoną dokładnością - w przypadku liczb zmiennoprzecinkowych jest to np. 64 bity. Zatem reszta cyfr zostaje odrzucona i ułamek 1/10 jest zapamiętany niedokładnie. Oczywiście błąd jest bardzo mały, ale jest! Jeśli teraz taką przybliżoną wartość ułamka pomnożymy przez 10, to wynik będzie równy około 1, ale NIE DOKŁADNIE 1. Teraz komputer porównuje ten wynik z wartością jeden i otrzymuje fałsz - wynik różni się od 1. Dlatego wykonana zostaje instrukcja po else.

Wynika stąd bardzo ważny wniosek na przyszłość - liczb zmiennoprzecinkowych NIE WOLNO przyrównywać do siebie, gdyż z powodu błędów zaokrągleń równość może nigdy nie wystąpić. Zamiast sprawdzania równości będziemy sprawdzali, czy różnica tych liczb jest dostatecznie mała. Jeśli tak, to przyjmiemy, że są równe. Jeśli nie, to przyjmiemy, że się różnią. Ponieważ różnica może być dodatnia lub ujemna, to będziemy badali jej moduł, czyli wartość bezwzględną.

 

Zamiast a == b stosujemy fabs(a - b) < EPS.

fabs(x) - funkcja obliczająca wartość bezwzględną z x. Wymaga dołączenia pliku nagłówkowego cmarh.
EPS - stała określająca założoną dokładność porównania.

 

Nasz program zmieniamy następująco:

 

// Porównywanie liczb double
// (C)2010 I LO w Tarnowie
//--------------------------

#include <iostream>
#include <cmath>

using namespace std;

const double EPS = 0.000000001;

int main()
{
    double x;

    x = 0.1;
    if(fabs(x * 10 - 1) < EPS) cout << "JEST OK\n";
    else                       cout << "JEST NIEDOBRZE\n";

    return 0;
}

 

Teraz jest już wszystko w porządku, gdyż różnica x * 10 - 1 jest bardzo bliska zera - mniejsza od stałej EPS.

 

// Rozwiązywanie równania kwadratowego
//   2
// ax + bx + c = 0
//
// (C)2010 I LO w Tarnowie
//-----------------------------------------

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

const double EPS = 0.000000001;

int main()
{
    double a,b,c,delta,x1,x2;

    cout << fixed << setprecision(6);

    cout << "ROWNANIE KWADRATOWE\n"
            "===================\n\n"
            "a = "; cin >> a;
    cout << "b = "; cin >> b;
    cout << "c = "; cin >> c;
    delta = b * b - 4 * a * c;
    cout << endl << "WYNIKI:\n\n";
    if(fabs(delta) < EPS)
    {
      // pierwiastek podwójny
      x1 = -b / 2 / a;
      cout << "X1 = X2 = " << x1 << endl;
    }
    else if(delta > 0)
    {
      // dwa pierwiastki
      x1 = (-b - sqrt(delta)) / 2 / a;
      x2 = (-b + sqrt(delta)) / 2 / a;
      cout << "X1 = " << setw(12) << x1 << endl
           << "X2 = " << setw(12) << x2 << endl;
    }
    else
    {
      // brak pierwiastków rzeczywistych
      cout << "BRAK\n";
    }

    return 0;
}

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe