Niesforne bity i bajty - slajdy z prezentacji


2019-01-18, 00:37

W tym tygodniu wyjątkowo nie pojawi się wpis tematyczny. Mam jednak dla Was - czytelników - coś w zamian: prezentację, którą wygłaszałem we wtorek na krakowskim meetupie sympatyków C++.

C++ User Group Krakow

Jeszcze w roku 2018 zostałem zaproszony przez Bartłomieja Filipka do uczestnictwa w cyklicznych spotkaniach grupy C++ User Group Krakow, których jest on współorganizatorem. Z racji wyjazdów związanych z moim obecnym zatrudnieniem oraz okresem świątecznym nie udało mi się w minionym roku pojawić na ani jednym spotkaniu. Nadszedł jednak nowy rok, a wraz z nim seria postanowień. Wśród nich pojawiło się, aby nie tylko uczestniczyć w spotkaniu, ale również zaprezentować naszego bloga wśród krakowskiej społeczności. Oczywiście, jak postanowiłem, tak też zrobiłem :)

Plan prezentacji

Samą prezentację podzieliłem na trzy części. Pierwszą z nich poświęciłem na zaprezentowanie społeczności naszego bloga. Przedstawiłem krótko cały nasz zespół, opisując wkład każdego członka zespołu. Następnie pokazałem wszystkim, że lubi nas już ponad (uwaga!) 700 osób! Mega. Już niedaleko do okrągłego 1024 :) Zamieściłem również statystyki oglądalności z pierwszych siedmiu miesięcy. Popatrzcie, jak ładnie te słupki rosną :) Pamiętajcie: wraz z ich wzrostem rośnie polska świadomość i wiedza na temat programowania w C++! I właśnie dlatego cieszy mnie ten wynik. Dodatkowo pokazałem, gdzie można nas znaleźć, bo - publikujemy wpisy w aż trzech miejscach:

Następnie przedstawiłem nasz główny cel, czyli:

Propagowanie wiedzy o nowoczesnym C++

Mała dygresja z mojej strony: jako programista na codzień pracujący w innej technologii bardzo często spotkałem się ze zdaniem, że C++ to język w którym pamięć gubiona jest na masę, a programiści na codzień walczą o przetrwanie. Wszyscy dookoła pamiętają jedynie język sprzed standardu C++11. Ja sam nie zgadzam się z tym sformułowaniem, dlatego robię (robimy!) to, co widać :)

Prezentację naszego bloga zakończyłem poprzez zaproszenie do współpracy wszystkich tych, którzy chcieli by wraz z nami walczyć o dobre imię C++. W tym miejscu pragnę zaprosić również Ciebie do współpracy - pomóż nam sprawić, aby wiedza o C++ rosła w naszym pięknym kraju.

Wracając do bitów i bajtów

Druga część prezentacji została poświęcona typom całkowitym oraz problemem, z którym spotykamy się na codzień, a który bardzo często potrafi być zbagatelizowany: Integer Overflow.

Aby wprowadzić publiczność w klimat, rozpocząłem od podstaw, które wszyscy znamy. Krótko wprowadziłem wszystkich czym są bity i bajty, a następnie przeszedłem do omówienia dwóch bardzo popularnych formatów kodowania liczb całkowitych do postaci binarnej. Mowa oczywiście o Kodzie Uzupełnień Do Jedności oraz o Kodzie Uzupełnień Do Dwóch. W kilku prostych przykładach przedstawiłem, czym różnią się pomiędzy sobą te dwa formaty. Jako kolejne przedstawiłem to, że Standard C++ niejawnie mówi nam o tym, że do kodowania liczb całkowitych stosowany jest Kod Uzupełnień Do Dwóch.

Kolejnym punktem spotkania było omówienie tego, czym jest zjawisko nazywane Integer Overflow, czyli przepełnienie typów całkowitych. Przedstawiłem trzy popularne sposoby na poradzenie sobie z tym problemem, po czym zagladnąłem do standardu, aby zobaczyć, co on ma do powiedzenia na ten temat. Okazało się, że o ile w przypadku typów bez znaku (unsigned) standard decyduje w pełni o zachowaniu, to w przypadku typów ze znakiem (signed) definiowane jest jako zachowanie niezdefiniowane, czyli Undefined Behavior.

Czym jest Undefined Behavior mam nadzieję, że wszyscy wiemy, ale dla potomnych:

  • Nie mamy pewności, co zostanie wykonane przez procesor
  • Kompilator zakłada, że niezdefiniowane zachowanie nigdy nie ma miejsca
  • Cała odpowiedzialność zostaje zrzucona na programistę

Omówiłem również różnice pomiędzy UB a Implementation Defined. Mianowicie, kiedy standard mówi, że konkretne zachowanie zależy od implementacji, to ma on na myśli implementację konkretnego kompilatora. Możemy w takim razie założyć konkretne zachowania kompilatora, na których będziemy się opierali i napisać do nich testy. W momencie, kiedy będziemy chcieli przenieść się na inny kompilator - wystarczy uruchomić testy i sprawdzić, czy aby na pewno wszystko jest tak, jak być powinno. Jeżeli mowa o Undefined Behavior, to tutaj nie możemy założyć nic, bo to co w chwili jego wystąpienia może się wydarzyć, może być zupełnie losowe. Przy dobrych wiatrach będzie to wypadkowa zachowań sprzętu, kompilatora oraz systemu operacyjnego. Dlatego nie możemy doprowadzić do wystąpienia UB w naszym kodzie.

Następne slajdy prezentowały, w jaki sposób radzić sobie z Integer Overflow. Zarówno tym występującym jawnie (suma) jak i tym, którego na pierwszy rzut oka nie widać. Przy temacie związanym z ukrytym Integer Overflow wyszedł temat Promocji Typu, który z racji wywołania musiał zostać przeze mnie podjęty. Dodatkowo, omówiłem również proces Konwersji Typu, który bardzo często jest mylony z promocją.

Po przykładach pokazujących, w jaki sposób można poradzić sobie (miejscowo) z Integer Overflow poruszyłem temat tego, co można zrobić bardziej globalnie, aby móc zapobiec przepełnieniu typów. Mowa oczywiście o Big Integer, czyli obiektach symulujących nieskończenie wielkie liczby całkowite¹. Spisałem również kilka drobnych wniosków na ich temat:

  • Każda cyfra przechowywana jest jako kolejny element tablicy (niekoniecznie w formie dziesiętnej)
  • Operacje na Big Integer-ach przypominają operacje pisemne stosowane w szkole podstawowej
  • Biblioteka standardowa C++ nie posiada implementacji dla Big Integer
  • Biblioteka Boost posiada implementację Big Integer: boost/multiprecision/cpp_int

Wspomniałem również o zaletach i wadach tego rozwiązania:

  • Zaleta: Ogarniamy duże liczby
  • Wada: Procesory natywnie nie wspierają Big Integer-ów
  • Wada: Im większa liczba, tym wolniej się liczy

Liczby liczby zmiennoprzecinkowe

Trzecią i ostatnią częścią mojej prezentacji był temat budowy liczb zmiennoprzecinkowych. Aby dobrze wejść w temat, najpierw wyjasniłem w jaki sposób działają ułamki bitowe. Wiedza na ich temat przydała się podczas kalkulacji związanych z liczbami zmiennoprzecinkowymi, dlatego postanowiłem powiedzieć o tym wcześniej.

O samych liczbach zmiennoprzecinkowych napisałem dwa osobne wpisy, które podlinkuję tutaj, abyście mogli dokładniej wejść w temat: Porozmawiajmy o pieniądzach, czyli standard IEEE 754 w praktyce, Porozmawiajmy o pieniądzach, czyli jak robić to dobrze.

To, czego brakuje w powyższych wpisach, to sposób w jaki możemy przejść z postaci dziesiętnej do postaci binarnej. Zachęcam Was w takim razie do prześledzenia slajdów (które udostępniam w linku niżej), ponieważ jest to wiedza warta zdobycia.

Na koniec prezentacji przedstawiłem rozwiązanie, które oferuje nam biblioteka Boost Multiprecision, czyli format liczb zmiennoprzecinkowych o większej podstawie niż standardowa dwójka. Ja w swoich przykładach użyłem typu o podstawie 100. Czy wiedzieliście, że są propozycje dodania do standardu typów zmiennoprzecinkowych o podstawie innej niż 2?

Ponieważ celem naszego zespołu jest szerzenie wiedzy na temat C++ (przede wszystkim nowoczesnego C++), postanowiłem opublikować slajdy, które były wyświetlane podczas prezentacji. Starałem się, aby można było wyciągnąć z nich maksymalnie dużo wiedzy, niekoniecznie słuchając samej prezentacji. Niesforne bity i bajty - ściągnij tutaj!

Moje wrażenia

To było moje pierwsze publiczne wystąpienie, dlatego miałem trochę stresu i obaw z nim związanych. Bałem się, że nie zdążę ze wszystkim, ale na szczęście wszystko się udało. Sama społeczność, z którą się spotkałem, bardzo miło mnie przyjęła. W kilku miejscach miałem błędy, które w bardzo profesjonalny sposób zostały mi przedstawione. Poznałem osobiście również Bartka - z którym mimo wspólnej współpracy nie miałem okazji się wcześniej poznać. Dzięki Bartku jeszcze raz za zaproszenie! :)

Spotkanie oceniam bardzo pozytywnie, i polecam wszystkim uczestnictwo w spotkaniach organizowanych przez C++ User Group Kraków, które odbywają się w każdy trzeci wtorek miesiąca.


¹ - Przy założeniu, że mamy nieskończenie wiele pamięci.



Marcin Kukliński

Zawodowo backend developer, hobbystycznie pasjonat języka C++. Po godzinach poszerza swoją wiedzę na takie tematy jak teorii kompilacji oraz budowa formatów plików. Jego marzeniem jest stworzyć swój własny język programowania.

Pssst! Używamy Cookies. Poprzez używanie naszego serwisu zgadzasz się na odczytywanie i zapisywanie Cookies w swojej przeglądarce.