День 06 · Условия: if, else, switch · страница 4 из 6

Трассировка ветвлений

В дне 02 трассировка отвечала на вопрос «что лежит в ячейках после каждой строки». С ветвлениями появляется второй вопрос: какие строки вообще выполнятся. На ревью чужого кода и на контрольной точке запустить программу нельзя — путь по веткам нужно пройти в голове.


Правила для ветвлений

Правила 1–6 дня 02 действуют: одна строка таблицы — одна выполненная строка внутри main, печать тоже; значения — после шага; прочерк - — переменной ещё нет; номера строк — по исходному файлу. Нумерация правил сквозная на весь курс, поэтому новые правила продолжают её — 7–10:

  1. Строка с if или } else if — шаг. На ней вычисляется условие. Условие только читает ячейки, поэтому значения в этой строке таблицы те же, что строкой выше.
  2. Строки } else { и } — не шаги. На них ничего не вычисляется.
  3. Строки невыполненных веток в таблицу не попадают. Номера строк идут с пропусками.
  4. После первой сработавшей ветки остальная цепочка — не шаги. Следующее } else if ниже не проверяется, его в таблице нет.

Ситуация. На складе 7 штук, в заказе 10. Программа решает, отгрузить заказ полностью, частично или никак.

Код для чтения · разбираем, набирать не нужно
 1  package main
 2
 3  import "fmt"
 4
 5  func main() {
 6  	stock := 7
 7  	ordered := 10
 8  	status := "полностью"
 9  	if stock == 0 {
10  		status = "нет"
11  	} else if stock < ordered {
12  		status = "частично"
13  		ordered = stock
14  	}
15  	fmt.Println(status, ordered)
16  }
шаг строка что происходит stock ordered status
1 6 создать stock 7 - -
2 7 создать ordered 7 10 -
3 8 создать status 7 10 полностью
4 9 7 == 0 — false, строка 10 пропущена 7 10 полностью
5 11 7 < 10 — true, заходим в блок 7 10 полностью
6 12 status получает «частично» 7 10 частично
7 13 ordered = stock → 7 7 7 частично
8 15 напечатать 7 7 частично
Пример · только посмотреть, набирать не нужно
stagiaire@lab:~/gocourse/day06/scratch$ go run .
частично 7

Строки 10 нет: её ветка не выполнилась. Строки 14 нет: это }.

Та же программа с stock := 20 идёт другим путём:

Образец · набирать не нужно
# шаг | строка | stock | ordered | status
1 | 6  | 20 | -  | -
2 | 7  | 20 | 10 | -
3 | 8  | 20 | 10 | полностью
4 | 9  | 20 | 10 | полностью
5 | 11 | 20 | 10 | полностью
6 | 15 | 20 | 10 | полностью
Вывод · это печатает программа, набирать не нужно
полностью 10

Оба условия проверялись и оба оказались false — поэтому шаги 4 и 5 есть, а строк 10, 12 и 13 нет. Таблица стала на две строки короче: по числу строк видно, какой путь прошла программа.


Какая ветка сработала: отладочная печать

Проверить путь запуском можно так же, как в дне 02, — отладочной печатью в копии программы в scratch. Первой строкой каждой ветки вставьте печать с номером строки из исходного файла:

Код для чтения · разбираем, набирать не нужно
	stock := 7
	ordered := 10
	status := "полностью"
	if stock == 0 {
		fmt.Println("строка 10")
		status = "нет"
	} else if stock < ordered {
		fmt.Println("строка 12")
		status = "частично"
		ordered = stock
	}
	fmt.Println(status, ordered)
Вывод · это печатает программа, набирать не нужно
строка 12
частично 7

Напечаталась только «строка 12» — программа прошла через вторую ветку. В подписях — номера строк исходной программы: в копии они сдвинулись.


Попробуйте сейчас: трассировка trace.

Цель: заполнить trace/table.txt без запуска — скидка и бесплатная доставка, сумма у каждого своя.

1. Посмотрите, что в папке задания:

▶ Выполните
cd ~/gocourse/day06/trace
ls

2. Шаги и номера строк в table.txt уже вписаны, и по ним виден путь. Поэтому сначала не открывайте table.txt: откройте только program.go, пройдите его в голове и выпишите на бумаге номера строк, которые выполнятся. Потом откройте table.txt и сверьте номера. Разошлось — найдите, в каком условии ошиблись.

3. Заполните все ? без запуска. Потом запустите — три числа в выводе совпадут с последней строкой таблицы: pct, delivery, pay:

▶ Выполните
go run .

4. Этот шаг — сверка уже заполненной таблицы, а не способ получить числа: смысл упражнения в том, чтобы ваши числа совпали, а не в том, чтобы их напечатала машина. Разошлось что-то в середине — вот копия, в которой можно дописать отладочную печать и найти, где именно (program.go при этом не меняйте):

▶ Выполните
cp program.go ~/gocourse/day06/scratch/main.go
cd ~/gocourse/day06/scratch
go run .

Готово, когда: в table.txt не осталось ?, три числа из вывода go run . совпали с последней строкой таблицы, и в course check 06 пункт «Таблица trace заполнена верно» (trace) отмечен ✔.


Задача с порогами: как её решать

В задании discount скидка зависит от суммы заказа: четыре ступени, пороги и проценты у каждого свои. Решаем по методу дня 05: условие → примеры → подцели → маленькие шаги → сверка.

Условие. cat TASK.txt. Выпишите пороги в копейках и проценты. Что печатать — три строки, их вид дан в условии.

Примеры. Одной своей суммы мало: она проверяет одну ступень из четырёх. Нужны примеры на каждую ступень и на каждый порог — сам порог и на копейку меньше. Посчитайте их на бумаге до кода. Для порогов 1000, 5000 и 10 000 руб. с процентами 2, 5 и 10 таблица примеров начиналась бы так:

sum, коп. Ступень Скидка, коп. К оплате, коп.
99999 меньше 1000 руб. 0 99999
100000 от 1000 руб. 2000 98000
499999 от 1000 руб. 9999 490000
500000 от 5000 руб. 25000 475000

В третьей строке 499999 × 2 / 100 = 9999,98, а целое деление отбрасывает дробь — 9999.

Подцели.

  1. Процент по сумме — цепочка else if. С какого порога начинать, решает правило порядка с третьей страницы.
  2. Скидка в копейках — по формуле из условия.
  3. К оплате — сумма минус скидка.
  4. Печать рублей и копеек: рубли — / 100, копейки — % 100, в Printf — %d.%02d (день 03). Знак процента в Printf — %%.

Маленькие шаги. Сначала только подцель 1: цепочка и печать процента. Прогоните её со всеми суммами из таблицы примеров, меняя число в строке sum :=. Когда процент верный на всех границах — добавляйте скидку, потом печать.

Сверка. Своя сумма из условия даёт ровно три строки из TASK.txt, граничные суммы — ваши примеры с бумаги. gofmt -l . ничего не печатает.


Что может пойти не так

Что видите Что это значит Что делать
Строк с шагами в таблице 9, а нужно 10 строку удалили или добавили переименовать table.txt, выполнить course lab 06, перенести значения в новую заготовку
Все ? заполнены, но где-то значение не совпало ошибка в каком-то шаге пройти заново по правилам; на строке с if значения те же, что строкой выше
discount: на сумме ровно на пороге — процент меньшей ступени > вместо >= сверить знак с условием
discount: у самой большой суммы процент средней ступени пороги в цепочке идут от меньшего к большему начать с большего порога
discount: копейки напечатаны одной цифрой — 312.5 вместо 312.05 в Printf %d вместо %02d %02d
discount: личная сумма прошла, запуск с другой суммой — нет в программе готовые числа вместо вычислений всё считать из sum
не нашёл в main.go строк с начальными значениями: sum первая строка main не такая, как в условии sum := число — первой строкой main

Попробуйте сейчас: задание discount.

Цель: discount/main.go считает скидку на всех порогах из своего TASK.txt и печатает три строки по образцу.

1. Прочитайте условие:

▶ Выполните
cd ~/gocourse/day06/discount
cat TASK.txt

2. Таблица примеров на бумаге, потом код по подцелям. Прогоните каждую границу из своей таблицы.

3. Верните свою сумму и выполните:

▶ Выполните
go run .
gofmt -l .

Готово, когда: каждая граница из таблицы дала на экране расчёт с бумаги, со своей суммой программа печатает три строки из TASK.txt, gofmt -l . ничего не печатает (пункты проверки discount, code_fmt).


Дальше: условия из нескольких частей — «и», «или», «не» — course next