Здесь все примеры будем нумеровать с префиксом «BOOL», ибо «B» было использовано в первой группе заданий. Так же нам часто понадобится слово выводящее «Истина» или «Ложь» в зависимости от результатов вычислений. Назовем его «B.».
: B. ( Bool -> ) \ Bool – Булева переменная, 0-Ложь, иначе Истина
IF ." True " ELSE ." False " THEN ;
Следует вас познакомить с переменной, типа Bool, а также с новой конструкцией вида:
IF ( B -> ) <Код если B = Истина> ELSE <Код если B = Ложь> THEN
где используется переменная такого типа. Bool в SP-Forth ничем не отличается от ранее используемых переменных целого типа, единственное отличие – это его интерпретация, когда она равна нулю, то это означает «Ложь», во всех остальных случаях кодируется «Истина». Встроенная константа в SP-Forth «FALSE» оставляет на стеке число «0», а «TRUE» - «4294967295(-1)». Вы также можете увидеть, что SP-Forth по-разному интерпретирует целые числа: либо без знака (4294967295), либо со знаком (-1). Конструкция «IF … ELSE … THEN» - это операторы ветвления кода. Слово «IF» берет со стека число и интерпретирует его как булеву переменную, в случае истины выполняет код между «IF … ELSE», иначе код между «ELSE … THEN», который не обязателен, тогда ничего не выполняется и продолжается интерпретация кода после «THEN». Упрощенный вариант кода будет таким: «IF … THEN». Теперь должна быть понятна работа слова «B.», если на стеке лежит «Bool», не равная нулю, тогда на экран печатается строка «True», иначе – «False».
Пример 1. Проверка числа на положительность.
: BOOL1 ( A -> )
0 > B.
;
5 BOOL1
True Ok
0 BOOL1
False Ok
-1 BOOL1
False Ok
Поясним дополнительно сравнение с нулем. В SP-Forth сначала пишем ноль («0») который пойдет в стек, затем слово больше («>»), которое берет 2 верхних элемента на стеке и сравнивает их, и в зависимости от результата оставляет булево значение либо «0», либо «-1», которое уже анализирует слово «B.». Стековая нотация слова «>» - ( NUMBER1 NUMBER2 -> BOOL ).
Пример 2. Проверка числа на нечетность.
: BOOL2 ( A -> )
2 MOD \ берем остаток от деления на 2
B. \ остаток 1 – истина, а 0 - ложь
;
3 BOOL2
True Ok
8 BOOL2
False Ok
Код «2 MOD» оставляет либо 0, либо 1, что можно интерпретировать как булево значение, таким образом на сей раз нам не нужно пользоваться оператором сравнения.
Пример 3. Проверка числа на четность. Отличается от предыдущего незначительно. Теперь остаток 0 – это истина, а 1 ложь. Меняется только интерпретация результата деления.
: BOOL3 ( A -> )
2 MOD \ берем остаток от деления на 2
0= B. \ остаток 1 – ложь, а 0 - истина
;
3 BOOL3
False Ok
8 BOOL3
True Ok
Строка «2 MOD» как в предыдущем случае, «0=» - проверка на чётность, ибо четное число дает остаток ноль при делении на два. И стандартный конец «B.» распечатка результата.
Пример 4. Проверка неравенств A>2 и B<=3.
: BOOL4 ( A B -> )
1- 3 < \ A B-1<3
SWAP 2 > \ B-1<3 A>2
AND \ одновременно B-1<3 и A>2
B.
;
В SP-Forth нет встроенного оператора сравнения «<=» (Меньше или равно, еще одну библиотеку подключить лень, а лень двигатель прогресса). Для этого мы воспользуемся искусственным приемом. Если «B<=3», то «B-1<3», так как мы работаем с дискретными целыми числами, то данный прием допустим. Оператор AND проверяет одновременность выполнения двух условий, это логическое умножение двух булевых переменных, оставленными как результаты двух сравнений.
3 3 BOOL4
True Ok
2 3 BOOL4
False Ok
3 4 BOOL4
False Ok
Если хотя бы одно из условий не выполняется – результат «False».
Пример 5. Проверка неравенств A>=0 и B<-2. Идентичен предыдущему.
: BOOL5 ( A B -> )
-2 < \ A B<-2
SWAP 1+ 0 > \ B<-2 A+1>0
AND \ одновременно B<-2 и A+1>0
B.
;
0 -3 BOOL5
True Ok
0 -2 BOOL5
False Ok
-1 -3 BOOL5
False Ok
1 -3 BOOL5
True Ok
Пример 6. Проверка неравенства A<B<C.
: BOOL6 ( A B C -> )
OVER > \ A B C -> A B C>B
ROT ROT < \ A B C>B -> C>B A<B
AND \ C>B A<B -> [C>B]AND[A<B]
B.
;
1 2 3 BOOL6
True Ok
1 1 2 BOOL6
False Ok
1 2 2 BOOL6
False Ok
Пример 7. Сводится к проверке неравенства A<=B<=C.
: BOOL7 ( A B C -> )
1+ OVER > \ A B C -> A B C+1>B
ROT 1- ROT < \ A B C+1>B -> C+1>B A-1<B
AND \ C>=B A<=B -> [C>=B]AND[A<=B]
B.
;
1 2 3 BOOL7
True Ok
1 1 3 BOOL7
True Ok
1 2 2 BOOL7
True Ok
3 2 2 BOOL7
False Ok
1 2 1 BOOL7
False Ok
Пример 8. Числа A и B нечетны одновременно.
: BOOL8 ( A B -> )
2 MOD SWAP 2 MOD AND \ остаток A/2 и остаток B/2
B.
;
3 5 BOOL8
True Ok
2 5 BOOL8
False Ok
3 8 BOOL8
False Ok
Пример 9. Хотя бы одно из двух чисел нечетно. Отличается от предыдущего заменой оператора AND на OR.
: BOOL9 ( A B -> )
2 MOD SWAP 2 MOD OR \ остаток A/2 или остаток B/2
B.
;
3 5 BOOL9
True Ok
2 5 BOOL9
True Ok
3 8 BOOL9
True Ok
2 8 BOOL9
False Ok
Оператор OR выдает ложь только в том случае, когда оба операторы «ложь», иначе «истина», а AND выдает истину, когда оба операнда «истина», иначе «ложь».
Пример 10. Только одно из двух чисел нечетно. Разница в замене оператора OR на XOR. Все эти булевы операторы имеют свои таблицы истинности и свою логику работы. Предполагается, что все это вы знаете или изучите самостоятельно.
: BOOL10 ( A B -> )
2 MOD SWAP 2 MOD XOR \ остаток A/2 XOR остаток B/2
B.
;
3 5 BOOL10
False Ok
2 5 BOOL10
True Ok
3 8 BOOL10
True Ok
2 8 BOOL10
False Ok
Пример 11. Два числа имеют одинаковую четность. Теперь же заменяем оператор XOR на знак равенства «=», то есть остатки от деления на два у обеих чисел должны быть одинаковыми - одинаковые остатки – одинаковая четность.
: BOOL11 ( A B -> )
2 MOD SWAP 2 MOD = \ остаток A/2 = остаток B/2
B.
;
3 5 BOOL11
True Ok
2 5 BOOL11
False Ok
3 8 BOOL11
False Ok
2 8 BOOL11
True Ok
Пример 12. Проверить что каждое из чисел A, B, C – положительное.
: BOOL12 ( A B C -> )
0 > \ A B C -> A B C>0
ROT 0 > AND \ A B C>0 -> B [C>0]AND[A>0]
SWAP 0 > AND \ B [C>0]AND[A>0] -> [C>0]AND[A>0]AND[B>0]
B.
;
1 2 3 BOOL12
True Ok
-1 2 3 BOOL12
False Ok
1 -2 3 BOOL12
False Ok
1 2 -3 BOOL12
False Ok
0 2 3 BOOL12
False Ok
1 0 3 BOOL12
False Ok
1 2 0 BOOL12
False Ok
Пример 13. Проверить что, хотя бы одно из чисел A, B, C – положительное. Получаем из предыдущего заменой AND на OR.
: BOOL13 ( A B C -> )
0 > \ A B C -> A B C>0
ROT 0 > OR \ A B C>0 -> B [C>0]OR[A>0]
SWAP 0 > OR \ B [C>0]OR[A>0] -> [C>0]OR[A>0]OR[B>0]
B.
;
0 0 -1 BOOL13
False Ok
1 0 -3 BOOL13
True Ok
Пример 14. Проверить, что ровно один из чисел A, B, C – положительное. Замена OR в предыдущем примере на XOR не решает проблему, так как в случае трех единиц «1 XOR 1 = 0», а «0 XOR 1 =1». Не мудрствую, лукаво можно ввести счетчик на вершине стека.
: BOOL14 ( A B C -> )
0 > IF 1 ELSE 0 THEN \ A B Count
ROT 0 > IF 1+ THEN \ B Count
SWAP 0 > IF 1+ THEN \ Count
1 = B. \ если счетчик = 1, то истина, иначе ложь
;
Описание кода:
- Первая строка – стандартное описание Форт-слова
- Если C>0, то на стеке оставляем 1, иначе 0. Это и будет нашим счетчиком
- Если A>0, то увеличиваем счетчик на единицу, иначе ничего не делаем
- Аналогично предыдущей строке обрабатываем B
- В пятой строчке сравниваем счетчик с единицей, если равно то истина, иначе ложь
1 2 3 BOOL14
False Ok
1 0 0 BOOL14
True Ok
-1 0 10 BOOL14
True Ok
Пример 15. Проверить, что ровно два из чисел A, B, C – положительные. Получим модификацией кода предыдущего примера. Заменим проверку равенства счетчика единице на два.
: BOOL15 ( A B C -> )
0 > IF 1 ELSE 0 THEN \ A B Count
ROT 0 > IF 1+ THEN \ B Count
SWAP 0 > IF 1+ THEN \ Count
2 = B. \ если счетчик = 2, то истина, иначе ложь
;
1 2 0 BOOL15
True Ok
0 2 3 BOOL15
True Ok
1 0 2 BOOL15
True Ok
-1 -2 0 BOOL15
False Ok
Пример 16. Проверить, что число одновременно четное и двузначное. Проверка на четность тривиальна и уже знакома, а двузначность означает, что число больше 9 и меньше 100.
: BOOL16 ( A -> )
DUP 9 > \ A -> A A>9
OVER 100 < AND \ A A>9 -> A [A>9]AND[A<100]
SWAP 2 MOD 0 = AND \ A [A>9]AND[A<100] -> [A>9]AND[A<100]AND{Остаток[A/2]=0}
B.
;
50 BOOL16
True Ok
8 BOOL16
False Ok
102 BOOL16
False Ok
51 BOOL16
False Ok
Можно сделать вычисления ленивыми, когда при невыполнении одного из условий остальные не проверяются. Такое возможно для операции AND (логического умножения), так как «0 AND Х = 0», при любом Х, для любого количества операндов «0 AND Х1 AND Х2 … AND ХN = 0».
: BOOL16 ( A -> )
DUP 9 > IF
DUP 100 < IF
2 MOD 0 =
B. EXIT
THEN
THEN
DROP 0 B.
;
Можете протестировать на тех же примерах первого варианта кода, самостоятельно, результаты идентичны. Из-за ленивых вычислений второй вариант кода должен в среднем выполняться быстрее. Какой вариант предпочтителен решайте сами.
Пример 17. Проверить, что число одновременно нечетное и трехзначное. Получаем небольшими модификациями кода предыдущего примера. Изменяем проверку «больше 9» на 99 и «меньше 100» на 1000. А проверку на четность заменяем на нечетность.
: BOOL17 ( A -> )
DUP 99 > \ A -> A A>99
OVER 1000 < AND \ A A>99 -> A [A>99]AND[A<1000]
SWAP 2 MOD AND \ A [A>99]AND[A<1000] -> [A>99]AND[A<1000]AND{Остаток[A/2]=1}
B.
;
999 BOOL17
True Ok
1000 BOOL17
False Ok
1001 BOOL17
False Ok
101 BOOL17
True Ok
Ленивый вариант с условным оператором.
: BOOL17 ( A -> )
DUP 99 > IF
DUP 1000 < IF
2 MOD
B. EXIT
THEN
THEN
DROP 0 B.
;
Пример 18. Проверить, что среди трех чисел есть хотя бы одна пара равных. То есть нужно запрограммировать проверку A=B или B=C или A=C.
: BOOL18 ( A B C -> )
2DUP = \ A B C -> A B C B=C
2SWAP OVER = \ A B C B=C -> C B=C A B=A
ROT OR \ C B=C A B=A -> C A [B=A]OR[B=C]
ROT ROT = OR \ C A [B=A]OR[B=C] -> [B=A]OR[B=C]OR[C=A]
B.
;
1 1 2 BOOL18
True Ok
1 2 2 BOOL18
True Ok
1 2 1 BOOL18
True Ok
1 2 3 BOOL18
False Ok
0 0 0 BOOL18
True Ok
При необходимости можно самостоятельно переписать с условным оператором.
Пример 19. Отличается от предыдущего заменой проверки условия равенства на равенство с противоположенным знаком, то есть A=-B или B=-C или A=-C.
: BOOL19 ( A B C -> )
2DUP NEGATE = \ A B C -> A B C B=-C
2SWAP OVER NEGATE = \ A B C B=-C -> C B=-C A B=-A
ROT OR \ C B=-C A B=-A -> C A [B=-A]OR[B=-C]
ROT ROT NEGATE = OR \ C A [B=-A]OR[B=-C] -> [B=-A]OR[B=-C]OR[C=-A]
B.
;
Новое слово NEGATE просто меняет знак числа на противоположенный.
1 2 3 BOOL19
False Ok
1 -1 0 BOOL19
True Ok
0 0 1 BOOL19
True Ok
0 1 -1 BOOL19
True Ok
2 2 -2 BOOL19
True Ok
Пример 20. Проверить, что у данного трехзначного числа все цифры различны. Можем свести к предыдущим примерам. Сначала число разобьём на цифры, затем проверим условия A<>B и B<>C и A<>C.
: BOOL20 ( ABC -> )
10 /MOD 10 /MOD \ ABC -> C B A
2DUP = \ C B A -> C B A B=A
2SWAP OVER = \ C B A B=A -> A B=A C B=C
ROT OR \ A B=A C B=C -> A C [B=C]OR[B=A]
ROT ROT = OR \ A C [B=C]OR[B=A] -> [B=C]OR[B=A]OR[A=C]
0 = B.
;
123 BOOL20
True Ok
110 BOOL20
False Ok
131 BOOL20
False Ok
199 BOOL20
False Ok
100 BOOL20
False Ok
- Первая строка стандартное объявление Форт-слова.
- Во-второй строке разбиваем число на цифры. Порядок получили обратный, но в нашем случае это не имеет никакого значения.
- Строки с третьей по шестой идентичны коду в примере 18. Если хотя бы одно из равенств будет истинным (A=B или B=C или A=C), то и результат будет истина.
- Тогда окончательно в строке семь проверяем равенство нулю результата, ибо только в этом случае все цифры будут различны, то есть A<>B и B<>C и A<>C.