Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Языки и методы программирования - лекция-5: выч...

Anton
December 08, 2024

Языки и методы программирования - лекция-5: вычислитель, принимающий решения: условные блоки и циклы в Си

Лекция курса "Языки и методы программирования"
Лекция-5: вычислитель, принимающий решения: условные блоки и циклы в Си
- Игра «угадай сумму» на Си
- Стандартная библиотека Си
- Ввод-вывод: libc
- Блоки с условиями (if)
- Условие: булево выражение
- Операторы сравнения — булевы выражения для блоков if
- Сложные условия из нескольких простых (логические операторы)
- Язык Си (реализация GNU C)
- Повторение действий: цикл
- Определение цикла и вложенных циклов Ады Августы Лавлейс
- Умножим два целых числа последовательностью сложений в цикле
- Выполнение программы с циклом по шагам
- Варианты циклов: for, while, бесконечный цикл, вложенные for
- Документация: язык Си (реализация GNU C)
- Практическое упражнение: разностный метод вычисления полинома
- Задания для самостоятельной работы

Anton

December 08, 2024
Tweet

More Decks by Anton

Other Decks in Education

Transcript

  1. Игра: «угадай сумму» • На входе два целых числа, читаем

    с клавиатуры • Если сумма этих чисел равна «68», мы выиграли — награда 100 очков • Если сумма этих чисел не равна «68», мы проиграли — награда 1 очко • Награда печатается на экран
  2. #include<stdio.h> int main() { int a, b; printf("a="); scanf("%d", &a);

    printf("b="); scanf("%d", &b); int sum = a + b; int prize; if(sum == 68) { prize = 100; } else { prize = 1; } printf("prize: %d\n", prize); }
  3. Стандартная библиотека Си • The GNU C Library (GNU libc)

    www.gnu.org/software/libc/manual/html_node/ index.html • cplusplus.com: Standard C++ Library reference / C Library cplusplus.com/reference/
  4. Ввод-вывод: libc • printf (stdio.h): 12.12 Formatted Output www.gnu.org/software/libc/manual/html_node/Formatte d-Output.html

    www.cplusplus.com/reference/cstdio/printf/ • scanf (stdio.h): 12.14 Formatted Input www.gnu.org/software/libc/manual/html_node/Formatte d-Input.html www.cplusplus.com/reference/cstdio/scanf/
  5. int sum = a + b; int prize; if(sum ==

    68) { prize = 100; } else { prize = 1; }
  6. Блоки с условиями if( условие ) { // действия, если

    условие выполнено // (ветка "ПРАВДА") ... } else { // действия, если условие не выполнено // (ветка "ЛОЖЬ") ... }
  7. Условие: булево выражение • FALSE (ЛОЖЬ): «0» • TRUE (ПРАВДА):

    «1», всё, что не «0» в памяти: • FALSE: [00000000] • TRUE: [00000001] • Значение можно записать в любой целочисленный тип (в int, char и т. п.) • В языке Cи специального типа для булевых значений нет, есть тип bool в С++
  8. Операторы сравнения — булевы выражения для блоков if • a

    == b : если a равно b, ПРАВДА, иначе ЛОЖЬ • a != b : если a не равно b, ПРАВДА, иначе ЛОЖЬ • a < b : если a меньше b, ПРАВДА, иначе ЛОЖЬ • a > b : если a больше b, ПРАВДА, иначе ЛОЖЬ • a <= b : если a меньше или равно b, ПРАВДА, иначе ЛОЖЬ • a >= b : если a больше или равно b, ПРАВДА, иначе ЛОЖЬ • a, b — численные значения, например, short, int, float, double, char, адреса (значения указателей) и т. п.
  9. Сложные условия из нескольких простых (логические операторы) • c &&

    d (логическое И): если c ПРАВДА И d ПРАВДА, ПРАВДА, иначе ЛОЖЬ • c || d (логическое ИЛИ): если c ПРАВДА ИЛИ d ПРАВДА, ПРАВДА, иначе ЛОЖЬ • !d (логическое НЕ): если d ЛОЖЬ, ПРАВДА, иначе ЛОЖЬ • c, d — булевы значения (ПРАВДА или ЛОЖЬ)
  10. Язык Си (реализация GNU C) • The GNU C Reference

    Manual www.gnu.org/software/gnu-c-manual/gnu-c- manual.html
  11. • 3 Expressions and Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Expressions-and-Operators • 3.6 Comparison

    Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Comparison-Operators • 3.7 Logical Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Logical-Operators
  12. int sum = a + b; int prize; if(sum ==

    68) { prize = 100; } else { prize = 1; }
  13. Замечание • Не путайте оператор сравнения «==» и оператор присвоения

    значения «=» • Если написать «if(a = b)», выражение «a = b» выполнит запись значения переменной b в переменную a, • при этом внутри блока if его результат будет распознан как TRUE • Компилятор вам такую конструкцию тоже разрешит
  14. #include<stdio.h> int main() { int a, b; printf("a="); scanf("%d", &a);

    printf("b="); scanf("%d", &b); int sum = a + b; int prize; if(sum == 68) { prize = 100; } else { prize = 1; } printf("prize: %d\n", prize); }
  15. Кстати • Можно посмотреть сгенерированный ассемблерный код • Это легко

    сделать в QtCreator: • собрать проект • поставить точку останова • запустить в режиме отладки (до точки останова) • выбрать меню: Отладка > Уровень инструкций • (если не запустить в режиме отладки, это меню не будет доступно) • В нашем случае ассемблерный код сгенерирован для архитектуры x86_64
  16. • cmpl: 68 в десятичной будет 0x44 в шестнадцатиричной •

    cmpl: устанавливает флаг «равно»/«не равно» • jne: осуществляет переход по адресу 0x400556, если cmpl выставила флаг «не равно» • по адресу 0x400556 расположен код «prize = 1» («не равно» = > проиграли) • если jne не прыгнула, то выполняется следующая строка «prize = 100» (НЕ «не равно» <=> «равно» => выиграли) • после этого безусловный прыжок jmp на адрес 0x40055d (print после цикла)
  17. $ mipsel-linux-gnu-gcc prog-branch-if.c -g -o prog-branch-if $ mipsel-linux-gnu-objdump -S prog-branch-if

    [...] int prize; //if(sum = 68) { // для проверки if(sum == 68) { 4007ec: 8fc30024 lw v1,36(s8) 4007f0: 24020044 li v0,68 4007f4: 14620005 bne v1,v0,40080c <main+0x5c> 4007f8: 00000000 nop prize = 100; 4007fc: 24020064 li v0,100 400800: afc20018 sw v0,24(s8) 400804: 10000003 b 400814 <main+0x64> 400808: 00000000 nop } else { prize = 1; 40080c: 24020001 li v0,1 400810: afc20018 sw v0,24(s8) } printf("prize: %d\n", prize); 400814: 8fc50018 lw a1,24(s8) [...]
  18. Варианты • if(...) {...} • if(...) {...} else {...} •

    if(...) {...} else if {...} else {...} • Еще: switch / case
  19. Определение цикла и вложенных циклов • Wherever a general term

    exists, there will be a recurring group of operations, as in the above example. Both for brevity and for distinctness, a recurring group is called a cycle. A cycle of operations, then, must be understood to signify any set of operations which is repeated more than once. It is equally a cycle, whether it be repeated twice only, or an indefinite number of times; for it is the fact of a repetition occurring at all that constitutes it such. In many cases of analysis there is a recurring group of one or more cycles; that is, a cycle of a cycle, or a cycle of cycles. Ada A. Lovelace, 1843
  20. Определение цикла и вложенных циклов • Везде, где существует общее

    правило, появится повторяющаяся группа операций, как в примере выше. Для краткости и определенности повторяющуюся группу операций будем называть циклом. Цикл операций, следовательно, следует понимать как обозначение множества операций, которые повторяются более одного раза. Одинаковым образом циклом будет являться двукратное повторение или повторение бесконечное количество раз; повторение вообще определяет цикл. В множестве ситуаций анализа может встретиться повторяющаяся группа одного или нескольких циклов; это будет цикл цикла или цикл циклов (вложенные циклы). Ада Лавлейс, 1843
  21. • Ада Лавлейс • Ввела в оборот определение цикла, бесконечного

    цикла, вложенных циклов • Цикл — повторяющаяся группа операций; любой набор операций, которые повторяются более одного раза • Вложенный цикл: цикл цикла, цикл циклов
  22. Умножим два целых числа • Последовательным сложением • (как механические

    арифмометры с множительной приставкой в XIX веке) • a * b = (a + a +...+ a) «b» раз
  23. Арифмометр Чебышева (1821-1894) • Первая версия — 1850-е годы •

    Сложение • Вычитание • Множительная и делительная приставки www.tcheb.ru
  24. Умножим два целых числа • a * b = (a

    + a +...+ a) «b» раз • Делаем «b» шагов • На каждом шаге: сумма = сумма + а • Сумма накапливается каждый шаг • На последнем шаге сумма превращается в произведение
  25. #include<stdio.h> int main() { int a = 9; int b

    = 100; // умножим a на b последовательным сложением int c = 0; for(int i = 0; i < b; i++) { //c = c + a; c += a; } // http://www.cplusplus.com/reference/cstdio/printf/ printf("%d*%d=%d\n", a, b, c); }
  26. Цикл for • Шаг 0: объявить и инициализировать переменные цикла

    • Шаг 1: проверить условие цикла - 1.1. FALSE: завершить - 1.2. TRUE: - 1.2.1. выполнить тело цикла - 1.2.2. выполнить действие после итерации цикла (обычно: обновить значение переменной цикла) - 1.2.3. перейти к Шагу 1
  27. $ mipsel-linux-gnu-gcc prog-loop-mul.c -g -o prog-loop-mul $ mipsel-linux-gnu-objdump -S prog-loop-mul

    [...] // умножим a на b последовательным сложением int c = 0; 4007dc: afc00018 sw zero,24(s8) for(int i = 0; i < b; i++) { 4007e0: afc0001c sw zero,28(s8) 4007e4: 10000008 b 400808 <main+0x58> 4007e8: 00000000 nop //c = c + a; c += a; 4007ec: 8fc30018 lw v1,24(s8) 4007f0: 8fc20020 lw v0,32(s8) [...] 400810: 0062102a slt v0,v1,v0 400814: 1440fff5 bnez v0,4007ec <main+0x3c> 400818: 00000000 nop //c = c + a; c += a; } printf("%d*%d=%d\n", a, b, c); [...]
  28. [...] // умножим a на b последовательным сложением int c

    = 0; 4007dc: afc00018 sw zero,24(s8) for(int i = 0; i < b; i++) { 4007e0: afc0001c sw zero,28(s8) 4007e4: 10000008 b 400808 <main+0x58> 4007e8: 00000000 nop //c = c + a; c += a; 4007ec: 8fc30018 lw v1,24(s8) 4007f0: 8fc20020 lw v0,32(s8) 4007f4: 00621021 addu v0,v1,v0 4007f8: afc20018 sw v0,24(s8) int a = 9; int b = 100; // умножим a на b последовательным сложением int c = 0; for(int i = 0; i < b; i++) { 4007fc: 8fc2001c lw v0,28(s8) 400800: 24420001 addiu v0,v0,1 400804: afc2001c sw v0,28(s8) 400808: 8fc3001c lw v1,28(s8) 40080c: 8fc20024 lw v0,36(s8) 400810: 0062102a slt v0,v1,v0 400814: 1440fff5 bnez v0,4007ec <main+0x3c> 400818: 00000000 nop //c = c + a; c += a; } printf("%d*%d=%d\n", a, b, c); [...]
  29. Некоторые варианты • for(;;) {...} — бесконечный цикл • while(1)

    {...} — тоже бесконечный цикл • break — выход из цикла в любой момент • Вложенный цикл: for(int i = 0; i < a; i++) { for(int j = 0; j < b; j++) { // ... } }
  30. Итого • Условные блоки «if» и циклы «for» — это

    типовые механизмы принятия решений, т. е. ветвления, выраженные в терминах языков высокого уровня • В основе обеих указанных (и всех прочих) конструкций лежит механизм управления счетчиком программы «pc» (program counter) • В случае с условным блоком «if» относительно текущей инструкции прыжок осуществляется вниз • В случае с циклом «for» относительно текущей инструкции прыжок осуществляется вверх
  31. Язык Си (реализация GNU C) • The GNU C Reference

    Manual www.gnu.org/software/gnu-c-manual/gnu-c- manual.html
  32. • 4 Statements https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Statements • 4.3 The if Statement

    www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#The-if-Statement • 4.7 The for Statement www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#The-for-Statement
  33. • 3 Expressions and Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Expressions-and-Operators • 3.6 Comparison

    Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Comparison-Operators • 3.7 Logical Operators https://www.gnu.org/software/gnu-c-manual/gnu-c- manual.html#Logical-Operators
  34. • Полином может численно приближать любую функцию непрерывную на заданном

    отрезке с заданной точностью • (нужно только подобрать степень и параметры полинома) • На исходной функции выбирается некоторое количество известных точек, через них проводится полином нужной степени • Использовался для табулирования функций (составления таблиц значений функций) в те времена, когда не было инструментов для их автоматического вычисления Польза
  35. Алгоритм • Пусть есть полином 2-й степени: T(x) = a

    * x^2 + b * x + c • При заданных параметрах a, b, c нужно вычислить последовательные значения полинома в точках: x = 0, 1, 2, 3, …, 100, … • (описание алгоритма: William Aspray, Computing before computers)
  36. • Возьмем полином: a = 1, b = 1, c

    = 41 T(x) = x^2 + x + 41 • Вычислим значения T(x) в 3-х точках вручную: x=0: T(0) = 0^2 + 0 + 41 = 41 x=1: T(1) = 1 + 1 + 41 = 43 x=2: T(2) = 2^2 + 2 + 41 = 47
  37. • Вычислим разности Δ [дельта] текущего значения T с предыдущим:

    Δ 1,0 = T(1) - T(0) = 43 - 41 = 2 Δ 2,1 = T(2) - T(1) = 47 - 43 = 4 • Вычислим разности Δ2 [дельта] второго порядка — текущего значения Δ с предыдущим: Δ2 = Δ 2,1 - Δ 1,0 = 2 • Легко убедиться, что разности 2-го порядка для заданного полинома 2-й степени будут повторяться (для полиномов высшего порядка постоянной останется разность высшей степени)
  38. • Теперь можем вычислить очередное значение Δ [дельта] по формуле:

    Δ2 = Δ 3,2 - Δ 2,1 => Δ 3,2 = Δ 2,1 + Δ2 = 4 + 2 = 6 • А очередное (ранее неизвестное) значение T(x=3) по формуле: Δ 3,2 = T(3) - T(2) => x=3: T(3) = T(2) + Δ 3,2 = 47 + 6 = 53 • Далее итеративно можно вычислить T(4), T(5), T(6) и т. п. до любого заданного x
  39. Задание 1: вычислить значения полинома разностным методом • Полином 2-й

    степени: T(x) = a * x^2 + b * x + c • На входе параметры: a, b, c • Самостоятельно вычисляем: T(0), T(1), T(2), Δ 1,0 , Δ 2,1 , Δ2 • Вычисляем в цикле: T(3), T(4), T(5), ... • Напечатать первые 100 значений: x = 0, … , 100 • Сверить результат с простым вычислением полинома по формуле
  40. Задание 2: решить квадратное уравнение • a * x^2 +

    b * x + c = 0 • Запросить коэффициенты a, b, c с клавиатуры • Решить квадратное уравнение при любых значениях a, b, c • Вывести корни или сообщить, что решений нет
  41. Замечания • #include<math.h> • Функция квадратный корень: sqrt • Типы

    данных с плавающей точкой: float или double • Для чтения с scanf типа double: «%lf» • Вывод printf для float/double: «%f» или «%.2f»
  42. Замечания • Если получили ошибку компиляции в духе: > gcc

    prog-branch-square-poli-root.c /tmp/ccAIcZCI.o: In function `main': prog-branch-square-poli-root.c:(.text+0x1ad): undefined reference to `sqrt' prog-branch-square-poli-root.c:(.text+0x1f4): undefined reference to `sqrt' collect2: error: ld returned 1 exit status • Добавить опцию «-lm» > gcc prog-branch-square-poli-root.c -lm
  43. Задание 3: чётное или нечётное число? • Получить на входе

    число • Напечатать: чётное оно или нечётное • Оператор «%» — остаток от деления: 8 % 2: 0 9 % 2: 1 15 % 4: 3
  44. Замечания • Если при компиляции получаете ошибку в духе: «объявление

    переменных внутри цикла for доступно только в стандарте c99» • нужно добавить опцию «-std=c99»: > gcc -std=c99 program.c