# Преговор - УПП, Седмица 3, 20.10.2023 \n [$presentation-controller] :title_slide35 # Цикли, assert :slide25 ## Бележки от миналия път :unordered - Видях две груби грешки в предадените решения, първо: ```cpp bool b; if (condition) b = true; Грешно е, понеже `[condition]` сам по себе си е от тип bool, с този `[if]` буквално не правите нищо. Правилния вариант е: ```cpp bool b = condition; Аналогично за: ```cpp bool b; if (!condition) b = true; правилното е: ```cpp bool b = !condition; :middle_slide :unordered - второ: ```cpp a >= 48 && a <= 57 .p Всяка буква действително съответства на определено число, дефинирано от ASCII стандарта. Наистина '0' е 48 и '9' е 57, обаче от вас =[не]= се очаква да помните ASCII таблицата! Също, ако не знаеш наизуст кои буква са тези числа, този израз е много неясен. .p Правилния вариант е просто да направите сравнения с буквите, все пак C++ ги "конвертира" (много грубо казано) към съответните ASCII стойности: ```cpp a >= '0' && a <= '9' :slide ## С/без загуба на данни [$br3] .p Получи се малко разногласие между това, което Ивана ви е казала и това което аз ви казах. В края на деня, =[конвертиране от int към unsigned int не губи информация!]= .p Цитирайки 4то издание на "The C++ Programming Language" глава 10.5: .quote A conversion is value-preserving if you can convert a value and then convert the result back to it's original type and get the original value Тоест, конвертирания при които не губиш битове, нямаш загуба на данни. :slide ## 2s compliment .p Интуитивно обяснение на 2s compliment. Да приемем, че работим с тип данни, при който имаме само 3 бита. .p Как бихме ги използвали, за да представим отрицателните числа? Най-лесния начин е да погледнем най-левия (старшия) бит, ако е 0 значи е положително, ако е 1 значи е отрицателно, тоест `[010]` е 2, докато `[110]` е -2. Ако разпишем всичките ни числа: ``` 111 -3 110 -2 101 -1 100 -0 011 3 010 2 001 1 000 0 :middle_slide .p Това работи, обаче имаме един гигантски проблем: събирането не работи! От математика знаем, че "2 - 1 = 2 + (-1)", тоест би трябвало да можем да съберем побитово 2 и -1 и да получим 1. Ама, ``` 2 + -1 = 010 + 101 = 111 = -3 .p Също, знаем, че "(-1) + (-1) = -2", обаче ``` -1 + -1 = 101 + 101 = 1010 имаме overflow, това се съкращава на 010 = 2 .p Излиза, че с тази схема не можем да събираме отрицателни числа както събираме положителни (или както събираме побитово). .p Да не говорим, че ние имаме -0, което не ни трябва много. :middle_slide Нека да помислим пак, да вземем само положителните: ``` 011 3 010 2 001 1 Сега, искаме -1 да бъде такова число, различно от досега дефинираните (тоест което има единица в старшия си бит) така че "1 + -1 = 0". Лесно се досещаме, че ако добавим към "001" числото "111", тогава тяхната сума ще предизвика overflow и резултата ще бъде 0: ``` 001 + 111 = 1000 overflow, става 000 Нека тогава "-1 = 111". :slide .p Правейки същото за "2 + -2", намираме че ``` 010 + 110 = 1000 overflow, става 000 Нека тогава "-2 = 110". За "3 + -3" се досещаме, че "-3 = 101". За сега имаме: ``` 111 -1 110 -2 101 -3 100 x 011 3 010 2 001 1 000 0 100 не сме го използвали, обаче намерихме отрицателното число за всяко положително. Да видим как работим с него, побитово "100 + 001 = 101", тоест "x + 1 = -3", следователно x ще бъде -4. :middle_slide .p Това е идеята на "complements", дефинираме отрицателни числа, така че да използваме едно и също събиране между положителни и отрицателни. .p Още от много старите "калкулатори" ([url https://en.wikipedia.org/wiki/Adding_machine сумиращи машини]), изваждането се е свеждало до събиране на положително и отрицателно число. .p И това е причината защо `[~ 2]` връща `[-3]`: ``` ~ 00000000000000000000000000000010 ────────────────────────────────── 11111111111111111111111111111101 И затова при `[>>]` със знаков тип имаме аритметическо отместване: ``` 11111111111111111111111111111101 >> 1 ───────────────────────────────────── 11111111111111111111111111111110 :slide ## Цикли [$br4] :unordered - `[while]` цикъл ```cpp while (условие) { тяло } "условие" е булева стойност, като ако е `[false]` цикъла спира, докато ако е `[true]` "тяло" се изпълнява и после пак се проверява условие :middle_slide - Може да си го представите като :code_cpp if (условие) { тяло } else { спри } if (условие) { тяло } else { спри } ... :slide :unordered - `[do-while]` цикъл, като `[while]`, но "тяло" се изпълнява поне един път ```cpp do { тяло } while (условие); Нашият аналог е: :code_cpp тяло if (условие) { тяло } else { спри } if (условие) { ... :middle_slide :unordered - `[for]` цикъл ```cpp for (инициализация; условие; инкрементация) { тяло } "инициализация" се изпълнява само веднъж, преди всичко останало в цикъла\n "условие" се изпълнява преди всяка итерация, като ако е `[false]` цикъла спира, докато ако е `[true]` продължава\n "инкрементация" се изпълнява след края на всяка итерация :slide :unordered - Може да си представяте, че това на практика извършва: :code_cpp инициализация if (условие) { тяло } else { спри } инкрементация if (условие) { тяло } else { спри } ... :middle_slide :unordered - или използвайки `[while]` цикъл: ```cpp инициализация while (условие) { тяло инкрементация } :slide ### Ключови думи [$br3] :unordered - `[break]`: моментално прекратява изпълнението на цикъла .p При `[for]` цикли инкрементацията не се изпълнява след `[break]` [$br2] - `[continue]`: продължи след края на сегашната итерация; тоест изпълнението на тяло се прекратява и започваме нова итерация .p При `[for]` цикли директно отива на инкрементация :slide ## Assert [$br3] .p Понякога е полезно да тестваме нашия код вътре в самия код. Тоест, искаме на конкретно място в кода да проверим нещо. ```cpp assert(condition); .p Ако `[condition]` е `[true]`, нищо не се случва, обаче ако е `[false]` програмата моментално прекратява изпълнение. .p Използва се повече като програмистки уред, тоест ако програмата спре заради `[assert]`, това е защото има някаква програмистка грешка.