Теперь мы решаем новую группу заданий с исключительно целочисленными параметрами. Все задания мы будем нумеровать с префиксом I, сокращение от Integer, означающее целое число.
Пример 1. Перевести см в м без округления. Здесь вы увидите всю красоту Форта.
Rm=Rcm/100 – целочисленно
: I1 ( Rcm -> Rm )
100 /
;
503 I1
Ok ( 5 )
Что означает в 503 см содержится 5 полных метров.
Пример 2. Отличается от предыдущего заменой 100 на 1000.
Mt= Mkg/1000
: I2 ( Mkg -> Mt )
1000 /
;
12683 I2
Ok ( 12 )
В 12683 кг 12 полных тонн.
Пример 3. Так же отличается от предыдущего константой. Теперь 1000 меняем на 1024.
DkB= DB/1024
: I3 ( DB -> DkB )
1024 /
;
2050 I3
Ok ( 2 )
2050 B - это 2 полных kB.
Пример 4. Так же простейшая задачка на целочисленное деление.
Для определенности A>B, результат равен A/B.
: I4 ( A B -> A/B )
/
;
15 4 I4
Ok ( 3 )
В отрезке длиной 15 размещается 3 целых отрезка длиной 4.
Пример 5. Отличается от предыдущего примера заменой целочисленного деления на взятие остатка от деления.
: I5 ( A B -> остаток{A/B} )
MOD
;
15 4 I5
Ok ( 3 )
15/4 – остаток равен 3 – все верно, результат теста корректный.
Примеры 1-5 настолько просты, что даже нет необходимости создавать соответствующие слова. Можно просто ввести число-операнд затем тело слова. Результат получите в скобках на стеке. Чтобы распечатать его и не засорять стек нажмите «.» и «Enter». Перепишем эти примеры для наглядности.
- «503 100 / .»
- «12683 1000 / .»
- «2050 1024 / .»
- «15 4 / .»
- «15 4 MOD .»
Но если вы будете часто пользоваться написанным кодом, крайне желательно создавать отдельные слова-функции, также дать им легко запоминающиеся осмысленные названия.
Пример 6. Вывести число десятков и единиц двузначного числа. Для этого используем операцию /MOD, которая одновременно вычисляет и целую часть, и остаток от деления.
: I6 ( AB -> A B )
10 /MOD SWAP
;
45 I6
Ok ( 4 5 )
Чтобы вывести в таком же порядке как на стеке слегка изменим код (помним, что сначала напечатается вершина стека, поэтому перед выводом используем команду SWAP)
45 I6 SWAP . .
4 5 Ok
Теоретически, последним штрихом, будет оформление вывода в отдельное слово, как говорилось ранее в предыдущей группе задач, по схеме:
: I6. I6 SWAP . . ;
Теперь окончательно задача решаться будет просто вызовом одного слова с одним аргументом:
45 I6.
4 5 Ok
Результат тот же, но решение выглядит более профессионально.
Разумеется, эти два слова можно объединить в одно по схеме:
: I6. 10 /MOD SWAP SWAP . . ;
: I6. 10 /MOD . . ;
Два слова SWAP уже не будут нужны, но так для сложных задач не рекомендуется делать, кроме того, как говорилось раннее интерфейс вывода и логику работы алгоритма крайне желательно отделять, так изменение в коде одного не повлияет на другое.
Пример 7. Вычислить сумму и произведение цифр двузначного числа. Дальнейшее развитие предыдущего примера.
: I7 ( AB -> A+B A*B )
10 /MOD \ AB -> A B
2DUP + \ A B -> A B A+B
ROT ROT * \ A B A+B -> A+B A*B
;
45 I7
Ok ( 9 20 )
Сумма цифр числа 45 равна 4+5=9, а произведение 4*5=20, тест корректен.
Если вас не удовлетворяет результат на стеке, то можете аналогично предыдущему примеру написать слово для вывода на экран.
Пример 8. Перестановка местами цифр в двузначном числе.
: I8 ( AB -> BA )
10 /MOD SWAP 10 * +
;
45 I8
Ok ( 54 )
Пример 9. Вывести число сотен в трехзначном числе.
: I9 ( ABC -> A )
100 /
;
578 I9
Ok ( 5 )
Все верно. Число сотен в числе 578 равно 5.
Пример 10. Аналогичен предыдущему. Выводим сначала число единиц затем десятков.
: I9 ( ABC ->C B )
10 /MOD 10 MOD
;
123 I9
Ok ( 3 2 )
Пример 11. Вычислить сумму и произведение цифр трехзначного числа.
: I11 ( ABC -> A+B+C A*B*C )
10 /MOD 10 /MOD \ ABC -> C B A
DUP 2OVER + + \ C B A -> C B A A+C+B
SWAP 2SWAP * * \ C B A A+C+B -> A+C+B A*C*B
;
456 I11
Ok ( 15 120 )
Сумма 4+5+6=15, а произведение 4*5*6=120.
Пример 12. Перевернуть трехзначное число справа на лево.
: I12 ( ABC -> CBA )
10 /MOD 10 /MOD \ ABC -> C B A
SWAP 10 * + \ C B A -> C BA
SWAP 100 * + \ C BA -> CBA
;
123 I12
Ok ( 321 )
Вот так просто Форт переворачивает трехзначное число «задом наперед».
Пример 13. В трехзначном числе сотни перенести в крайнее правое положение, вместо единиц.
: I13 ( ABC -> BCA )
100 /MOD \ ABC -> BC A
SWAP 10 * + \ BC A -> BCA
;
123 I13
Ok ( 231 )
Пример 14. Аналогичен предыдущему. Довольно несложная задачка.
: I14 ( ABC -> CAB )
10 /MOD \ ABC -> C AB
SWAP 100 * + \ C AB -> CAB
;
123 I14
Ok ( 312 )
Пример 15. В трехзначном числе переставить цифры сотен и десятков местами.
: I15 ( ABC -> BAC )
10 /MOD 10 /MOD \ ABC -> C B A
10 * SWAP 100 * + + \ C B A -> BAC
;
123 I15
Ok ( 213 )
Как и прежде, сначала разбираем число на цифры, затем собираем, в требуемом условиями задачи, порядке.
Пример 16. Поменять местами десятки и единицы в трехзначном числе.
: I16 ( ABC -> ACB )
10 /MOD 10 /MOD \ ABC -> C B A
100 * + SWAP 10 * + \ C B A -> ACB
;
123 I16
Ok ( 132 )
Пример 17. Довольно тривиальная задачка. В числе, большем 999, определить число сотен.
: I17 ( A -> X ) \ X – число сотен
1000 MOD 100 /
;
123456 I17
Ok ( 4 )
Пример 18. Абсолютно идентична предыдущему примеру и также примитивна. В аналогичном числе найти число тысяч.
: I18 ( A -> X ) \ X – число тысяч
10000 MOD 1000 /
;
123456 I18
Ok ( 3 )
Пример 19. Дано S секунд перевести в количество полных минут M.
: I19 ( S -> M ) \ M – результат в минутах
60 /
;
179 I19
Ok ( 2 )
Пример 20. Аналогична предыдущему. Переводим секунды S в число полных часов H.
: I20 ( S -> H ) \ H – результат в часах
3600 /
;
7201 I20
Ok ( 2 )
Пример 21. Идентична примеру 19, только вычисляем количество секунд с последней минуты.
: I21 ( S -> Sm ) \ Sm – результат в секундах
60 MOD
;
179 I21
Ok ( 59 )
Пример 22. Аналогична примеру 20, определяем число секунд с последнего часа.
: I22 ( S -> Sh ) \ Sh – результат в секундах
3600 MOD
;
7201 I22
Ok ( 1 )
Пример 23. В отличии от предыдущего, определяем число минут с последнего часа.
: I23 ( S -> Sm ) \ Sm – результат в минутах
3600 MOD 60 /
;
7201 I23
Ok ( 0 )
Пример 24. Определить день недели. Дан номер дня D (1-365). Известно, что 01.01 – ПН.
: I24 ( D -> W ) \ W – номер дня недели, 0 - ВС, 1 - ПН и т. д.
7 MOD
;
8 I24
Ok ( 1 )
Пример 25. Отличается от предыдущего тем, что 01.01 – ЧТ.
: I25 ( D -> W ) \ W – номер дня недели, 0 - ВС, 1 - ПН и т. д.
3 + 7 MOD
;
8 I25
Ok ( 4 )
Прибавили 3, чтобы синхронизировать день недели с остатком от деления. Так как остаток от деления 1 на 7 равно 1, а 1 – это ПН. Остаток (1+3)/7 равна 4, что кодирует ЧТ.
Забегая вперед, расскажу вам как протестировать слова I24 и I25, пробежав по всем вариантам в цикле, не погружаясь глубоко в сам код.
Тест слова I24:
: TEST-I24
366 1 DO I . .” - день года - “ I I24 . .” код дня недели" CR LOOP
;
Тест слова I25:
: TEST-I25
366 1 DO I . .” - день года - “ I I25 . .” код дня недели" CR LOOP
;
По-прежнему, чтобы вызвать тест данных слов нужно набрать соответствующие имена («TEST-I24», «TEST-I25»). Вводите по одному, чтобы результаты не сливались в одно.
Пример 26. Теперь 01.01 – ВТ. Синхронизируем день недели и сводим задачу к предыдущим двум.
: I26 ( D -> W ) \ W – номер дня недели, 0 - ВС, 1 - ПН и т. д.
1 + 7 MOD
;
1 I26
Ok ( 2 )
Соответствующее тест-слово:
: TEST-I26
366 1 DO I . .” - день года - “ I I26 . .” код дня недели" CR LOOP
;
Пример 27. Ничем не отличается от предыдущих трех примеров, за исключением числа синхронизации к условию задачи 01.01 – СБ.
: I27 ( D -> W ) \ W – номер дня недели, 0 - ВС, 1 - ПН и т. д.
5 + 7 MOD
;
1 I27
Ok ( 6 )
Очередное тест-слово:
: TEST-I27
366 1 DO I . .” - день года - “ I I27 . .” код дня недели" CR LOOP
;
Пример 28. «Квинтэссенция» предыдущих примеров № 24-27, и их решение в общем виде. Дано по-прежнему номер дня D в диапазоне 1-365 и кодировка дня недели. Как и ранее необходимо вычислить код дня недели для D.
: I28 ( D N -> W ) \ W – номер дня недели, 0 - ВС, 1 - ПН и т. д.
+ 1- 7 MOD
;
С параметром N=1 сводится к примеру 24.
8 1 I28
Ok ( 1 )
С параметром N=4 сводится к примеру 25.
8 4 I28
Ok ( 4 )
С параметром N=2 сводится к примеру 26.
1 2 I28
Ok ( 2 )
С параметром N=6 сводится к примеру 27.
1 6 I28
Ok ( 6 )
Тест-слово для 28-ого примера:
: TEST-I28
366 1 DO I . .” - день года - “ I OVER I28 . .” код дня недели" CR LOOP DROP
;
Вызвать нужно следующим образом «6 TEST-I28», где задается только параметр N, в данном случае суббота. Примеры работ тест-слов не приводятся по причине большого объема однотипного текста.
Пример 29. Определить какое количество квадратов со стороной C покрывает прямоугольник со сторонами A и B без наложений, а также площадь свободной части.
: I29 ( A B C -> N {A*B-N*C^2} ) \ N - количество квадратов {A*B-N*C^2} - площадь свободной части
DUP 2OVER \ A B C -> A B C C A B
ROT / ROT ROT OVER / ROT * \ A B C C A B -> A B C [A/C]*[B/C]=N - количество квадратов
SWAP DUP * OVER * \ A B C N -> A B N N*C^2
2SWAP * SWAP - \ A B N N*C^2 -> N {A*B-N*C^2}=площадь свободной части
;
11 21 5 I29
Ok ( 8 31 )
Целая часть от деления 11 на 5 равна 2, а 21 на 5 - 4, следовательно, без наложения размещается 2*4=8 квадратов со стороной 5 (что и выдает Форт-слово в качестве первого аргумента). Площадь прямоугольника равна 11*21= 231. Так, что путем нехитрого расчета получаем вычитанием из последней - площадь восьми квадратов, равной 8*5*5=200, то есть 231-200=31, а это второй аргумент работы вышеописанной функции. Тест Форт-слова корректен.
Пример 30. Определить столетие по году. Началом столетия считается хх01-ый год, поэтому мы вычитаем 1, чтобы избавиться от этого исключения. Незабываем что хх54-ый год – это хх+1-ое столетие, что учитывается прибавлением единицы.
: I30 ( Y -> C ) \ C - столетие
1- 100 / 1+
;
1901 I30
Ok ( 20 )
А вот 1900 год всё еще XIX век.
1900 I30
Ok ( 20 19 )