Здесь все примеры будем нумеровать с префиксом «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, то истина, иначе ложь
;

Описание кода:

  1. Первая строка – стандартное описание Форт-слова
  2. Если C>0, то на стеке оставляем 1, иначе 0. Это и будет нашим счетчиком
  3. Если A>0, то увеличиваем счетчик на единицу, иначе ничего не делаем
  4. Аналогично предыдущей строке обрабатываем B
  5. В пятой строчке сравниваем счетчик с единицей, если равно то истина, иначе ложь

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

  1. Первая строка стандартное объявление Форт-слова.
  2. Во-второй строке разбиваем число на цифры. Порядок получили обратный, но в нашем случае это не имеет никакого значения.
  3. Строки с третьей по шестой идентичны коду в примере 18. Если хотя бы одно из равенств будет истинным (A=B или B=C или A=C), то и результат будет истина.
  4. Тогда окончательно в строке семь проверяем равенство нулю результата, ибо только в этом случае все цифры будут различны, то есть A<>B и B<>C и A<>C.