Zmienne, odpowiedzi cz. 2 - Programowanie jest łatwe

Im dalej w las tym więcej drzew. Tutaj demonstruję rozwiązania dotyczące zmiennych zmiennoprzecinkowych oraz zmiennych znakowych. Może być zaskakująco!

spoon.jpg

Im dalej w las tym więcej drzew. Tutaj demonstruję rozwiązania dotyczące zmiennych zmiennoprzecinkowych oraz zmiennych znakowych. Może być zaskakująco!

Wartości zmiennoprzecinkowe

Co się stanie, gdy zapiszesz do zmiennej typu float wartość 1?

float jeden = 1;

Wydawać by się mogło, że zmienna przechowuje wartość równą jeden. Gdy wyświetlimy zawartość zmiennej, otrzymamy zaskakujący wynik:

printf("%08X", jeden);

To wyświetli nam wartość 42817BE8. Dlaczego? Ponieważ wartość zmiennoprzecinkowa jest przechowywane w pamięci w postaci "Mantysa | Eksponenta" (czyli wartość całkowita.wartość zmiennoprzecinkowa), a ostateczna wartość zmiennej jest wynikiem mnożenia mantysy przez eksponentę. Trzeba uważać!

  1. Co się stanie, gdy porównasz wartość zmiennej z ćwiczenia 1 ze zmienną typu int o wartości 1?

Naturalnie, gdy będziemy porównywać tą wartość z wartością 1, wynik porównania będzie prawdziwy:

float jedne = 1.0;
if (jeden == 1) {
  printf("rowne!");
}

Ale tylko dlatego, że załatwia to za nas kompilator. W momencie, gdy porównujemy te dwie wartości (float i int) następuje niejawna konwersja (tzw. rzutowanie) wartości float na int. Stąd wynik porównania jest prawdziwy.

  1. Jak rozwiążesz problem błędu liczb rzeczywistych, gdy np. musisz zwiększać jej wartość o ułamek w każdym obiegu pętli?

Ten klasyczny problem rozwiązuje się następująco: iteratorem pętli jest wartość całkowita a wynik zwiększenia uzyskuje się poprzez pomnożenie iteratora przez początkową wartość zmiennoprzecinkową:

int i = 0;
float ulamek = 0.23;
float wartoscWynikowa = 0;
for (i = 0; i < 10000; i++) {
    wartoscWynikowa = i * 0.23;
}

Dzięki temu mamy pewność, że przy każdym obiegu pętli wartoscWynikowa jest obarczona najmniejszym możliwym błędem.

  1. Co się stanie, gdy wprowadzisz wartość 99999999999999999 do zmiennej typu float? Wynik będzie naprawdę zaskakujący!
 float jeden = 99999999999999999;
 printf("%f", jeden);

Wynikiem będzie… 99999998430674944.000000. Dzieje się tak, ponieważ następuje przepełnienie miejsca, w które jest przeznaczone na przechowywanie mantysy. Wypróbuj powyższy kod z jeszcze większą wartością. Wniosek jest jeden: nigdy nie przechowuj dużych wartości w zmiennych zmiennoprzecinkowych.

  1. Jak zadeklarujesz zmienną zmiennoprzecinkową bez znaku ze zwiększoną precyzją? Deklaracja będzie wyglądać następująco: unsigned double long zmienna; Dla lubiących żarty, można się pokusić na stary dowcip programistów: double long joe;

Wartości znakowe

Pod jaką wartością, w ASCII, przechowywany jest znak spacji? 32

  1. Co się stanie po dodaniu dwóch wartości znakowych 'u' i 'p'? 'u' znajduje się pod wartością 117 a 'p' pod 112. Suma tych dwóch to 229. Wyświetlony znak będzie zależeć od użytej strony kodowania,

  2. Czy można mnożyć wartości znakowe?

Tak

char a = 'a';
char b = 'z';

char c = a * b;
int d = a*b;

printf("wartosc c = %c; wartosc d = %d", c, d);

Wynik: wartosc c = :, wartosc d = 11834. Zacznijmy od ostatniej wartości d = 11834 ponieważ 'a' posiada wartość 98 w tablicy ASCII a 'z' 122. 98 * 122 = 11834. Zmienna c natomiast przechowuje dwukropek, ponieważ nastąpiło wielokrotne przepełnienie jej maksymalnej wartości (char posiada maksymalnie 1 bajt, czyli przechowuje maksymalnie 256 wartości od 0 do 255). Wystarczy wykonać operację modulo (reszta z dzielenia), aby otrzymać wartość znaku, który będzie wynikiem działania: 11834 % 256 = 58. Pod wartością 58 kryje się właśnie dwukropek.

  1. Napisz pętlę, która wyświetli kolejne litery alfabetu od a do z.
char litera = 'a';
while (litera <= 'z') {
  printf("%c", litera);
  litera += 1;
}

Zmienna litera ustawiona jest początkowo jako 'a'. Następnie pętla będzie wykonywać się tak długo, dopóki litera będzie mniejsza lub równa 'z'. Można porównywać wartości znakowe identycznie jak wartości liczbowe.

  1. Napisz pętlę, która wyświetli kolejne litery alfabetu od A do Z. W zasadzie można użyć powyżej pętli powyżej, zmieniając jedynie wartości z 'a' na 'A' i 'z' na 'Z', jednak dla sportu, może tak:

    int znak = 65;
    while (znak <= 90) {
    printf("%c", znak);
    znak += 1;
    }

    Specjalnie użyłem zmiennej int, która niby nie ma nic wspólnego ze znakami, aby zademonstrować możliwość naprzemiennego korzystania z wartości znakowych i liczb całkowitych.

  2. Czym się różni mała litera od wielkiej litery? Dokładnie 32 znakami pomiędzy 'A' kryje się pod wartością 65 a 'a' pod 97.

  3. Sortując znaki alfabetu, która litera będzie pierwsza: 'a' czy 'A'? Dlaczego? Jak wynika ze wcześniejszego pytania, litera 'A' posiada mniejszą wartość w tablicy, więc będzie posortowana jako pierwsza, gdy zaczniemy od najmniejszej. Czyli duże litery są pierwsze wg informatycznej kolejności alfabetycznej.

Dodano: 2018-03-16 07:31 przez Piotr Poźniak

ćwiczenia , odpowiedzi , zmienne , float , zmiennoprzecinkowe , znaki , ascii ,
Piotr Poźniak
O autorze:

Programuję od ponad 15 lat. Prowadzę software house. Angażuję i zachęcam wszystkich do programowania w ramach inicjatywy Programowanie jest łatwe.