Translated using translate google. The original language is Russian. Original page https://hi-aga.ru/index.php/homepage/if-1-30

This group of tasks is devoted exclusively to the conditional operator “IF”.

Example 1. If the given integer is positive, then increase it by one, otherwise do nothing.

: IF1 ( A -> {[A++]OR[A]} )
    DUP 0 >\A->A Bool
    IF 1+ THEN .
;
5 IF1
6 Ok
0 IF1
0 Ok
-5 IF1
-5 Ok

The “IF” construction takes the number A from the stack, if it is true (any number not equal to zero), then the instructions up to the THEN keyword are executed, that is, it increases it by one, in this case, otherwise it immediately goes to the code after “THEN”.

The SP-Forth system has special constants "TRUE" and "FALSE" that can be executed. They leave corresponding numbers on the stack, so you can see that SP-Forth encodes truth with the number “-1”. These constants and logical expressions can control the flow of the program.

Example 2. An additional condition “otherwise” is added to the previous example. For this purpose, SP-Forth has a special word ELSE. The whole structure looks like this:

IF (code is executed if the condition is true) ELSE (otherwise, that is, when false) THEN
: IF2 ( A -> {[A++]OR[A-2]} ) \ A>0: ? A++, A-2
    DUP 0 >\A ->A Bool
    IF 1+ ELSE 2- THEN .
;
5 IF2
6 Ok
0 IF2
-2 Ok
-5 IF2
-7 Ok

Example 3. Differs from the previous one by adding an additional condition, when equal to zero. Let's add just one line after the description.

: IF3 ( A -> ) \ {[A++]OR[A-2]OR[10]}
    DUP 0 = IF DROP 10 . EXIT THEN
    DUP 0 >
    IF 1+ ELSE 2- THEN . ;
10 IF3
11 Ok
0 IF3
10 Ok
-10 IF3
-12 Ok

Example 4. In a set of three numbers, determine the number of positive ones. You need to set up a counter and check each number separately. If true the counter is incremented by one. At the end we display its value.

: IF4 ( A B C -> N ) \ N= number of positive
    0 \ A B C -> A B C 0 (0 – counter)
    SWAP 0 > IF 1+ THEN \ A B C 0 -> A B N
    SWAP 0 > IF 1+ THEN \ A B N -> A N
    SWAP 0 > IF 1+ THEN \ A N -> N
    .
;
1 2 3 IF4
3 Ok
0 0 0 IF4
0 Ok
-1 -2 -3 IF4
0 Ok
-1 0 2 IF4
1 Ok

Example 5. Modification of the previous example, adding the number of negative numbers. Let's create two variables - the number of positive (N+) and negative numbers (N-). Let's initialize them to zero.

VARIABLE N+
VARIABLE N-
: IF5 ( A B C -> ) \ N+ = number of positive N- = number of negative
    0 N+ ! 0 N- ! \ initialization of N+ and N- to zeros
    DUP 0 > IF DROP N+ @ 1+ N+ ! ELSE \ if C>0, then N+ is increased by one
        0 < IF N- @ 1+ N- ! THEN \ A B C -> A B, if C<0, then increase N-
    THEN
    DUP 0 > IF DROP N+ @ 1+ N+ ! ELSE \ similar for B
        0 < IF N- @ 1+ N- ! THEN\A B -> A
    THEN
    DUP 0 > IF DROP N+ @ 1+ N+ ! ELSE\for A
        0 < IF N- @ 1+ N- ! THEN\A ->
    THEN
    N+ @ . \ print the number of positive numbers first
    N-@. \ then negative
;
1 2 3 IF5
3 0 Ok
-1 0 1 IF5
1 1 Ok
0 0 0 IF5
0 0 Ok

If you do not reset N+ and N-, then each time you call the word “IF5” the number of positive and negative numbers will be summed with the previous values, and the result will be incorrect. This problem will not occur if the result is left on the stack, as in the code below, without using variables.

: IF5 ( A B C -> ) \ N+ = number of positive N- = number of negative
    0 0 \ A B C -> A B C 0 0 (0 0 - counters N+ and N-)
    ROT DUP 0 > IF DROP SWAP 1+ SWAP ELSE
        0 < IF 1+ THEN \ A B C -> A B N+ N-
    THEN
    ROT DUP 0 > IF DROP SWAP 1+ SWAP ELSE
        0 < IF 1+ THEN \ A B -> A N+ N-
    THEN
    ROT DUP 0 > IF DROP SWAP 1+ SWAP ELSE
        0 < IF 1+ THEN \ A -> N+ N-
    THEN
    SWAP. \ print the number of positive numbers first
    . \ then negative
;

Let everyone decide for themselves which option is simpler and clearer. Both options are good for educational purposes. A special feature of Forth is that in many problems you can do without explicit declaration of variables.

Example 6. Output the larger of two numbers (find the maximum). We duplicate both numbers and compare them, then delete the smaller one and display the result on the screen.

: IF6 ( A B -> MAX[A,B] )
    2DUP > \ A B -> A B A>B
    IF DROP ELSE SWAP DROP THEN .
;
1 2 IF6
2 Ok
2 1 IF6
2 Ok
1 1 IF6
1 Ok
-1 -2 IF6
-1 Ok
0 -1 IF6
0 Ok

Example 7. Similar to the previous one. Determine the smaller of the two numbers and print the serial number. We compare without saving the original data, since we send only the minimum number for printing.

: IF7 ( A B -> number_of_min[A,B] )
    >\A B -> A>B
    IF 2 ELSE 1 THEN .
;
1 2 IF7
1 Ok
2 1 IF7
2 Ok
1 1 IF7
1 Ok

If there is an equality, it displays the first of them, which is not an error in principle.

Example 8. Print two numbers in descending order. Similar to Example 6. Simple sorting of two numbers.

: IF8 ( A B -> MAX[A,B] MIN[A,B] )
    2DUP > \ A B -> A B A>B
    IF SWAP THEN. .
;
1 2 IF8
2 1 Ok
2 1 IF8
2 1 Ok
3 3 IF8
3 3 Ok

Example 9. Redistribute the values ​​of variables A and B. Assign the minimum to A, and the maximum to B.

First, let's create these real type variables. Then we assign them input values. Next is a standard check. Exchange values ​​if necessary.

FVARIABLE A FVARIABLE B
: IF9 ( A B -> ) \ A=MIN[A,B] B=MAX[A,B]
    B F! \ save the value in B
    A F! \ save the value in A
    A F@ B F@ FOVER FOVER F< \ -> A B A<B
    IF FDROP FDROP ELSE A F! B F! THEN \ if A<B delete A B, otherwise swap values
    A F@ F. \ print A
    B F@ F. \ print B
;
12E-1 -12E-1 IF9
-1.2000000 1.2000000 Ok
-12E-1 12E-1 IF9
-1.2000000 1.2000000 Ok

The second and third lines save the user's input into variables A and B. The fourth reads them, duplicates and compares them, the result of which is processed by the fifth, either removing values ​​from the stack that are not needed for replacement, or saving them by swapping them.

SP-Forth allows you to solve this example without using variables. The code is much simpler in this case.

: IF9 ( A B -> ) \ A=MIN[A,B] B=MAX[A,B]
    FOVER FOVER F<\A B -> A B A<B
    IF FSWAP THEN \ if A<B, because the vertex will be printed first
    F.F.
;
12E-1 -12E-1 IF9
-1.2000000 1.2000000 Ok
-12E-1 12E-1 IF9
-1.2000000 1.2000000 Ok

The result is the same, but the code has been reduced by almost half.

Example 10. Similar to the previous one. Instead of swapping values, we assign zero if A and B are equal, and the sum A+B, otherwise. The declaration of variables is now based on the conditions of the problem of an integer type:

VARIABLE A VARIABLE B
: IF10 ( A B -> )
    B! A! \ saving in A and B
    A @ B @ 2DUP = \ A B -> A B A=B
    IF 2DROP 0 ELSE + THEN \ if A=B, then leave X=zero, otherwise the sum X=A+B
    DUP A! B! \ X-> A=X B=X
    A@. \ print A
    B@. \ print B
;

Here is the result of the work written above:

5 10 IF10
15 15 Ok
3 3 IF10
0 0 Ok

And in this example there is no need to create variables. A simplified version would look like this:

: IF10 ( A B -> )
    2DUP = \ A B -> A B A=B
    IF 2DROP 0 ELSE + THEN \ if A=B, then leave X=zero, otherwise the sum X=A+B
    DUP. .
;
5 10 IF10
15 15 Ok
3 3 IF10
0 0 Ok

The result is identical, and the word is not only shorter, but also simpler.

Example 11. If A=B, then assign A and B zero, otherwise the maximum of A and B. First, we will write as in the condition with variables, similar to the previous example.

: IF11 ( A B -> )
    B! A! \ saving A and B
    A @ B @ 2DUP = \ A B -> A B A=B
    IF 2DROP 0 ELSE \ if A=B, then leave X=zero, otherwise X=MAX[A,B]
    2DUP > IF DROP ELSE SWAP DROP THEN \ if A>B, then X=A, otherwise X=B
    THEN
    DUP A! B! \ X-> A=X B=X
    A@. \ print A
    B@. \ print B
;
50 100 IF11
100 100 Ok
0 0 IF11
0 0 Ok
10 10 IF11
0 0 Ok
100 50 IF11
100 100 Ok

Now, with a sense of accomplishment, we can write a simplified version without using variables.

: IF11 ( A B -> )
    2DUP = \ A B -> A B A=B
    IF 2DROP 0 ELSE \ if A=B, then leave X=zero, otherwise X=MAX[A,B]
    2DUP > IF DROP ELSE SWAP DROP THEN \ if A>B, then X=A, otherwise X=B
    THEN
    DUP. .
;

The test results are the same (check it yourself), but the program is smaller and clearer.

Example 12. Determine the minimum from three numbers.

: IF12 ( A B C -> MIN[A,B,C] )
    2DUP <\A B C -> A B C B<C
    IF DROP ELSE SWAP DROP THEN \ A B C -> A MIN[B,C]
    2DUP < \ A MIN[B,C] -> A MIN[B,C] A<MIN[B,C]
    IF DROP ELSE SWAP DROP THEN \ A MIN[B,C] -> MIN{A,MIN[B,C]}
    .
;
1 2 3 IF12
1 Ok
-1 -2 -3 IF12
-3 Ok
10 0 -10 IF12
-10 Ok

In principle, the code should be clear, nothing complicated, first we find out the minimum from B and C, and then again the minimum, but from A and MIN[B,C].

Example 13. From three numbers, determine the average (which lies between the minimum and maximum).

: IF13 ( A B C -> X )          \ MIN[A,B,C]<=X<= MAX[A,B,C]
    2DUP >                     \ A B C -> A B C B>C
    IF SWAP THEN               \ A B C -> A B C    – «(B C) - отсортировано»
    DUP 2OVER DROP <           \ A (B C) -> A (B C) C<A
    IF . 2DROP EXIT ELSE       \ A (B C) ->        – «(B C A) - отсортирован», C-среднее
    DUP 2OVER >                \ A (B C) -> A (B C) C A>B, если A>B, то A-среднее
    IF 2DROP DROP . EXIT ELSE  \ A B C C ->        -  A-среднее
    2DROP . DROP EXIT THEN     \ иначе B-среднее
    THEN
;
1 2 3 IF13
2  Ok
3 2 1 IF13
2  Ok
2 1 3 IF13
2  Ok
2 3 1 IF13
2  Ok
1 3 2 IF13
2  Ok
3 1 2 IF13
2  Ok
-1 -2 -3 IF13
-2  Ok
-1 0 -2 IF13
-1  Ok
-1 0 1 IF13
0  Ok


If the operating logic is not clear, then you can perform a full sort, then select the middle element (the second in an array of three numbers).

: IF13 ( A B C -> X ) \ MIN[A,B,C]<=X<= MAX[A,B,C]
    2DUP > \ A B C -> A B C B>C
    IF SWAP THEN \ A B C -> A (B C) – “(B C) - sorted”
    DUP 2OVER DROP <\A (B C) -> A (B C) C<A
    IF ROT ELSE \ A (B C) -> (B C A) – “(B C A) - sorted”, C-average
    DUP 2OVER > NIP \ A (B C) -> A (B C) A>B, if A>B, then A-average
    IF ROT SWAP THEN \ A (B C) C -> (B A C), otherwise B-average we do nothing
    THEN
    DROP. DROP \ (A B C) -> - “in place B there will always be a middle element”
;

Gives the same results on the same data. Everyone can see this for themselves. NIP, similar to DROP, removes an element on the stack, but not the top, but the penultimate one, which is “beneath it”.

The third option is a combination of two examples solved earlier. First, the smallest is determined and removed (example 12), then the maximum is found from the remaining two (example 6), and we also remove it. To do this, let's rework example 12 a little.

: IF12 ( A B C -> X Y )  \ X Y - 2 числа из A B C, кроме минимума
    2DUP >               \ A B C -> A B C B>C
    IF SWAP THEN         \ A B C -> A (B C), «(B C) - отсортирован», теперь минимум либо B, либо A
    DUP 2OVER > NIP      \ A (B C) -> A (B C) C A>B
    IF SWAP DROP ELSE    \ A (B C) C A>B -> A C, если A>B, то B-минимум
    ROT DROP THEN        \ A (B C) C A>B -> (B C), иначе A
    . .                  \ вывод оставшихся двух чисел
;
1 2 3 IF12
3 2  Ok
1 3 2 IF12
3 2  Ok
2 1 3 IF12
3 2  Ok
2 3 1 IF12
3 2  Ok
3 1 2 IF12
2 3  Ok
3 2 1 IF12
2 3  Ok
-1 -2 -3 IF12
-2 -1  Ok
-1 0 -2 IF12
0 -1  Ok
-1 0 1 IF12
1 0  Ok


On test data, the minimum element is correctly removed. Now example 6 should remove the maximum element.

: IF6 ( A B -> X ) \ X-remaining after removing MAX[A,B]
    2DUP <\ A B -> A B A<B
    IF DROP ELSE NIP THEN
;

In example 12, we delete the penultimate line of displaying the processed numbers on the screen. They will be parameters for example 6. Finally we get:

: IF12 ( A B C -> X Y ) \ X Y - 2 numbers from A B C, except the minimum
    2DUP > \ A B C -> A B C B>C
    IF SWAP THEN \ A B C -> A (B C), "(B C) - sorted", now the minimum is either B or A
    DUP 2OVER > NIP \ A (B C) -> A (B C) A>B
    IF SWAP DROP ELSE \ A (B C) A>B -> A C, if A>B, then B is the minimum
    ROT DROP THEN \ A (B C) A>B -> (B C), otherwise A
;

Now example 13 will finally take the form:

: IF13 ( A B C -> X ) \ MIN[A,B,C]<=X<= MAX[A,B,C]
    IF12 IF6.
;

The shortest and simplest version of Example 13, not counting the reworking of two previously written examples.

Example 14. Now from three numbers we derive the minimum and then the maximum. It’s not for nothing that in the previous example we tinkered with the third version of its solution, through two other examples. Let's rework example 12 so that we do not delete the minimum, but print it on the screen.

: IF12 ( A B C -> X Y ) \ X Y - 2 numbers from A B C, except the minimum
    2DUP > \ A B C -> A B C B>C
    IF SWAP THEN \ A B C -> A (B C), "(B C) - sorted", now the minimum is either B or A
    DUP 2OVER > NIP \ A (B C) -> A (B C) A>B
    IF SWAP. ELSE \ A (B C) A>B -> A C, if A>B, then B is the minimum
    ROT. THEN \ A (B C) A>B -> (B C), otherwise A
;

Let's rewrite example 6 so that it prints MAX[A,B] and removes the extra number from the stack.

: IF6 ( A B -> ) \ print MAX[A,B]
    2DUP > \ A B -> A B A>B
    IF DROP ELSE SWAP DROP THEN .
;

It remains to assemble Example 14 from two changed words.

: IF14 ( A B C -> )  \ распечатать MIN[A,B] распечатать MAX[A,B]
   IF12 IF6 ;
1 2 3 IF14
1 3  Ok
1 3 2 IF14
1 3  Ok
2 1 3 IF14
1 3  Ok
2 3 1 IF14
1 3  Ok
3 1 2 IF14
1 3  Ok
3 2 1 IF14
1 3  Ok
-1 -2 -3 IF14
-3 -1  Ok
-1 0 -2 IF14
-2 0  Ok
-1 0 1 IF14
-1 1  Ok


Example 15. Of three numbers, find the sum of the two largest ones. Unlike the previous one, we first look for the maximum of three, then the second maximum of the remaining two and print their sum.

: IF12 ( A B C -> X Y ) \ X Y - 2 numbers from A B C, except the minimum
   2DUP > \ A B C -> A B C B>C
   IF SWAP THEN \ A B C -> A (B C), "(B C) - sorted"
   ROT OVER OVER <\A (B C) -> (B C) A C<A
   IF ROT ROT ELSE \ (B C) A C<A -> A (B C), if A>C, then A-maximum
   ROT THEN \ (B C) A C<A -> C A B, otherwise C-maximum
;

After the operation of the rewritten word IF12, there is a maximum on the stack (A if A>C or C otherwise), followed by the two remaining original numbers. It remains to find the maximum of the remaining modified word IF6.

: IF6 ( A B -> MAX[A,B] )
   2DUP <\ A B -> A B A<B
   IF SWAP THEN
   DROP
;

Now the main word of Example 15 will call up the words written above and add the results of their work. The first word IF12 finds the maximum and sends it to place “A”, then “IF6”, similarly, having determined the second maximum, puts it to place “B”, removing the third minimum element.

: IF15 ( A B C -> ) \ MAX1[A,B,C]+MAX2[A,B,C]
   IF12 IF6 + .
;
1 2 3 IF15
5 Ok
-1 -2 -3 IF15
-3 Ok
0 1 2 IF15
3 Ok

Example 16. If the given real numbers FA, FB, FC are ordered in ascending order, then double them, otherwise replace them with the opposite. In a stack comment, the notations "F:" and "I:" indicate which stack the changes occur on (real or integer). Our initial data is of a real type, and therefore all work with them is carried out in the appropriate place, but the results of their comparison go into the integer stack, and therefore you should pay special attention to this in order to eliminate any errors in understanding the code, and incorrect manipulations with data, in As a result, either there will not be enough data, or there will be “extra” data left, the balance on the two stacks will be disrupted due to erroneous manipulations on the “wrong stack”.

FVARIABLE FA FVARIABLE FB FVARIABLE FC
: IF16 ( FA, FB, FC -> )
    FC F! FB F! FA F!        \ F: FA FB FC ->
    FA F@ FB F@ F<           \ I: -> FA<FB
    FB F@ FC F@ F< AND IF    \ I : [FA<FB]AND[FB<FC]
        FA F@ 2E F* FA F!    \ FA= FA*2
        FB F@ 2E F* FB F!    \ FB= FB*2
        FC F@ 2E F* FC F!    \ FC= FC*2
    ELSE                     \ Иначе заменяем на противоположенные
        FA F@ FNEGATE FA F!  \ FA= -FA
        FB F@ FNEGATE FB F!  \ FB= -FB
        FC F@ FNEGATE FC F!  \ FC= -FC
    THEN
    FA F@ F.                 \ Печатаем результат в FA
    FB F@ F.                 \ FB.
    FC F@ F.                 \ FC.
;

In the second line we save the values ​​into variables
In the third and fourth, we read the values ​​​​from the variables and compare “FA<FB” and “FB<FC”, if both are true, then the original numbers form an increasing sequence, and, therefore, it is necessary to double the original numbers, which is what lines five to seven do .
Otherwise, we change the sign to the opposite, which is what lines ten to twelve do.
And we finally check the result by printing out the changed variables in lines fourteen to sixteen.
Let's check the word's performance on test data.

11E-1 21E-1 31E-1 IF16
2.2000000 4.2000000 6.2000000  Ok
31E-1 21E-1 11E-1 IF16
-3.1000000 -2.1000000 -1.1000000  Ok
1E 2E 3E IF16
2.0000000 4.0000000 6.0000000  Ok
2E 2E 3E IF16
-2.0000000 -2.0000000 -3.0000000  Ok
1E 2E 2E IF16
-1.0000000 -2.0000000 -2.0000000  Ok

Example 17. If the given real numbers FA, FB, FC are ordered in ascending or descending order, then double them, otherwise replace them with the opposite. We get it from the previous example by adding an additional condition, checking for decrease, i.e. double comparison FA>FB>FC. The standard list of words includes only comparisons of real numbers with “less” - “F<” (there is no word “F>”), so let’s replace the two comparisons “FA>FB and FB>FC” with “FB<FA and FC<FB” , because it’s too lazy to look for libraries with such words, and laziness is the engine of progress. If you need the word "F>" in the future, you can use this definition:

: F> ( FA FB -> FA>FB ) FSWAP F< ;

And the words “F>=”, “F<=” and “F<>” (not equal, can be denoted as “F!=”) are defined as follows:

: F>= ( FA FB -> FA>=FB ) FOVER FOVER F> F= OR ;
: F<= ( FA FB -> FA<=FB ) FOVER FOVER F< F= OR ;
: F<> ( FA FB -> FA<>FB )  F= 0= ;                              
: F!= ( FA FB -> FA!=FB ) F= 0= ;
2E 3E F>= B.
False  Ok
3E 2E F>= B.
True  Ok
3E 3E F>= B.
True  Ok
2E 3E F<= B.
True  Ok
3E 2E F<= B.
False  Ok
3E 3E F<= B.
True  Ok
2E 3E F!= B.
True  Ok
3E 3E F!= B.
False  Ok
2E 3E F<> B.
True  Ok
3E 3E F<> B.
False  Ok
FVARIABLE FA FVARIABLE FB FVARIABLE FC
: IF16 ( FA, FB, FC -> X1 X2 X3 )
    FC F! FB F! FA F!          \ F: FA FB FC ->
    FA F@ FB F@ F<             \ I: -> FA<FB
    FB F@ FC F@ F< AND         \ I: -> [FA<FB]AND[FB<FC]
    FB F@ FA F@ F<             \ I: -> [FA<FB]AND[FB<FC] FB<FA
    FC F@ FB F@ F< AND OR      \ I : [FA<FB]AND[FB<FC]OR[FB<FA]AND[FC<FB]
    IF  FA F@ 2E F* FA F!      \ FA= FA*2
        FB F@ 2E F* FB F!      \ FB= FB*2
        FC F@ 2E F* FC F!      \ FC= FC*2
    ELSE                       \ Иначе заменяем на противоположенные
        FA F@ FNEGATE FA F!    \ FA= -FA
        FB F@ FNEGATE FB F!    \ FB= -FB
        FC F@ FNEGATE FC F!    \ FC= -FC
    THEN
    FA F@ F.                   \ Печатаем результат в FA
    FB F@ F.                   \ FB.
    FC F@ F.                   \ FC.
;


Let's put into separate words three sections of code that change the value of the variables to the opposite, double them and print out the results. These manipulations are not at all necessary, they are purely for clarity. By unloading the body of the word IF17, we pay more attention to the logic of its operation.

: -FA-FB-FC ( -> )
    FA F@ FNEGATE FA F!  \ FA= -FA
    FB F@ FNEGATE FB F!  \ FB= -BA
    FC F@ FNEGATE FC F!  \ FC= -CA
;
: 2*FAFBFC ( -> )
    FA F@ 2E F* FA F!    \ FA= FA*2
    FB F@ 2E F* FB F!    \ FB= FB*2
    FC F@ 2E F* FC F!    \ FC= FC*2
;
: FAFBFC. ( -> )
    FA F@ F.             \ Печатаем результат в FA
    FB F@ F.             \ FB.
    FC F@ F.             \ FC.
 
;

Now let's rewrite IF17:

: IF17 ( FA, FB, FC -> )
    FC F! FB F! FA F!      \ F: FA FB FC ->
    FA F@ FB F@ F<         \ I: -> FA<FB
    FB F@ FC F@ F< AND     \ I: -> [FA<FB]AND[FB<FC]
    FB F@ FA F@ F<         \ I: -> [FA<FB]AND[FB<FC] FB<FA
    FC F@ FB F@ F< AND OR  \ I : [FA<FB]AND[FB<FC]OR[FB<FA]AND[FC<FB]
    IF   2*FAFBFC          \ FA= FA*2 FB= FB*2 FC= FC*2
    ELSE -FA-FB-FC         \ Иначе заменяем на противоположенные
    THEN
    FAFBFC.
;

Checking how the word works:

1E 2E 3E IF17
2.0000000 4.0000000 6.0000000  Ok
3E 2E 1E  IF17
6.0000000 4.0000000 2.0000000  Ok
1E 2E 1E  IF17
-1.0000000 -2.0000000 -1.0000000  Ok
1E 4E 3E IF17
-1.0000000 -4.0000000 -3.0000000  Ok
3E 2E 3E IF17
-3.0000000 -2.0000000 -3.0000000  Ok

It's up to you to decide which option you prefer. If everything is clear in the first option, then the second is a clear example of code structuring; not all tasks will be so trivial, and it will be useful to develop skills in competent code organization from the very beginning. Maybe not everyone will like the style when many operators are written on one line, for example “FC F@ FB F@ F< AND OR”. It's a matter of taste. Experienced programmers will be able to remake the style themselves, but I don’t like increasing the number of lines. Stack comments should dispel any unclear points in the code.

Example 18. Determine the number of a number in a set of three integers that is not equal to two others that are equal to each other.

: IF18 ( A B C -> N )            \ N={A,B,C}
    2DUP =                       \ A B C -> A B C B=C
    IF 2DROP DROP 1 . EXIT THEN  \ Если B=C, то «A» – искомое, печатаем 1 и выходим, иначе, B<>C,
                                 \ но тогда либо A=B, либо A=C
    DROP =                       \ A B C -> A=B , если истина, то «C» №3
    IF 3 ELSE 2 THEN .           \ иначе, «B» №2
;
1 2 2 IF18
1  Ok
2 1 2 IF18
2  Ok
1 1 2 IF18
3  Ok

First, the equality B=C is checked. The execution of which means that it is unequal to the other two, that is, the desired number is A, number one. We type “1” and exit. Otherwise, there are two possible options: either A=B or A=C. It is enough to check one of the conditions. To be sure, A=B is checked. If the equality is true, then the required number is third, otherwise it is second.

Example 19. Similar to the previous example, with the difference that four integers are given.

: IF19 ( A B C D -> N ) \ N={A|B|C|D}
    2DUP = \ A B C D -> A B C D C=D
    IF DROP IF18 EXIT THEN \ if C=D we remove D and reduce the problem to the previous one, otherwise either C or D is the required one, unequal to the other three
    DROP = \ A B C D -> A B= C - if true, then the desired D, No. 4
    IF 4 ELSE 3 THEN . \ otherwise C, No. 3
    DROP
;

Let's check the written word:

2 1 1 1 IF19
1 Ok
1 2 1 1 IF19
2 Ok
1 1 2 1 IF19
3 Ok
1 1 1 2 IF19
4 Ok

It's simple. First check C=D. Execution of which means that the required number is not among them. To make our work easier, the last number is removed, which allows us to reduce the problem to the previous one. Otherwise, the required number is either C or D. Thus, the search circle is sharply narrowed. It is enough to check which of these two numbers differs from the others that are equal to each other. To be sure, B=C is checked, if true we print 4, otherwise 3.

Example 20. Given 3 points FA, FB, FC. Determine which of the last two is closer to the first, and determine this distance.

To solve this example, you need to compare two modules: |FA-FB|<|FA-FC|. If true, print the point “B” and the distance |FA-FB|, otherwise “C” and, accordingly, |FA-FC|.

: IF20 ( FA, FB, FC -> )  \ {«B» |FA-FB|} или {«C» |FA-FC|}
    FC F! FB F! FA F!
    FA F@ FB F@ F- FABS   \ |FA-FB|
    FA F@ FC F@ F- FABS   \ |FA-FB| -> |FA-FB| |FA- FC|
    F<                    \ |FA-FB| |FA- FC| -> |FA-FB|<|FA- FC|
    IF   .” B “ FA F@ FB F@ F- FABS F.
    ELSE .” C “ FA F@ FC F@ F- FABS F.
    THEN
;
1E 2E 3E IF20
B 1.0000000  Ok
1E 5E 3E IF20
C 2.0000000  Ok


Example 21. Analyze a point with integer coordinates (X,Y).

If the coordinates of the point are (0,0), then output 0.
If the coordinates of the point are (x,0), then output 1.
If the coordinates of the point are (0,y), then output 2.
Otherwise, print 3.
: IF21 ( X Y -> N )
    2DUP 0 = SWAP 0 = AND \ X Y -> X Y {Y=0}AND{X=0}
    IF 2DROP 0 . EXIT THEN \ If {Y=0}AND{X=0}, then print “0” and exit
    0 = \ X Y -> X Y=0
    IF DROP 1 . EXIT THEN \ If {Y=0}, then print “1” and exit
    0 = \ X -> X=0
    IF2. EXIT THEN \ If {X=0}, then print “2” and exit
    3. \ Otherwise we print “3”
;

Written word test:

0 0 IF21
0 Ok
1 0 IF21
1 Ok
0 1 IF21
2 Ok
1 2 IF21
3 Ok

Example 22. Given a point with coordinates (X,Y), which does not lie on the coordinate axes. Determine which quarter it lies in.

To do this, you need to check the following inequalities:

X>0 and Y>0 – 1st quarter.
X<0 and Y>0 – 2nd quarter.
X<0 and Y<0 – 3rd quarter.
X>0 and Y<0 – 4th quarter.
Note that in the first two Y is positive, and in the rest it is negative. It is logical to first check for positivity of Y, thereby narrowing the search, then check X, finally localizing the quarter.

: IF22 ( X Y -> N )  \ N – координатная четверть
    0 >              \ X Y -> X Y>0    - если истина тогда либо 1-ая, либо 2-ая четверть
    IF 0 >           \ X -> X>0        - если истина, тогда 1-ая четверть, иначе 2-ая
    IF .” 1-ая четверть” ELSE .” 2-ая четверть” THEN
    ELSE 0 >         \ X -> X>0        - иначе либо 3-я, либо 4-ая четверть
    IF .” 4-ая четверть” ELSE .” 3-я четверть” THEN
    THEN
;
\ Протестируем:
1 1 IF22
1-ая четверть Ok
-1 1 IF22
2-ая четверть Ok
-1 -1 IF22
3-я четверть Ok
1 -1 IF22
4-ая четверть Ok

Example 23. Given the integer coordinates of the three vertices of a rectangle, the sides of which are parallel to the coordinate axes, use them to determine the coordinates of the fourth side. To solve this problem, we will use the solved example IF18. Since x4={x1|x2|x3} (that is, either x4=x1, or x4=x2, or x4=x3), and the one that is not equal to the other two, which are equal to each other, the problem is greatly simplified. This follows from the conditions of the problem, from the fact that the sides are parallel to the coordinate axes, therefore, the coordinates of two pairs of vertices whose abscissas are equal (these pairs of vertices form sides parallel to the OY axis). The same applies equally to the y-coordinates of all vertices, that is, y4={y1|y2|y3} } (or y4=y1, or y4=y2, or y4=y3).

: IF23 ( X1 Y1 X2 Y2 X3 Y3 -> X4 Y4)
    Y! X! \ X1 Y1 X2 Y2 X3 Y3 -> X1 Y1 X2 Y2
    ROT SWAP Y @ \ X1 Y1 X2 Y2 -> X1 X2 Y1 Y2 Y3
    IF18\X1 X2 Y1 Y2 Y3 -> X1 X2 Y4
    ROT ROT X @ \ X1 X2 Y4 -> Y4 X1 X2 X3
    IF18 SWAP\Y4 X1 X2 X3 -> X4 Y4
;

For the word to work correctly, let’s rewrite subtask IF18 so that it leaves on the stack not the number of the number, but the coordinate itself.

: IF18 ( A B C -> N ) \ N={A|B|C}
    2DUP = \ A B C -> A B C B=C
    IF 2DROP EXIT THEN \ If B=C, then A is the desired one, leave “A”, otherwise, B<>C, but then either A=B or A=C
    ROT ROT 2DUP = \ A B C -> A=B
    IF 2DROP ELSE –ROT 2DROP THEN
;

Of course, IF18 must be entered before calling it, otherwise there will either be an error if you have not entered it before, or the old option will work and the result will be incorrect.

1 1 1 3 7 3 IF23
 Ok (7 1)

Example 24. Calculate the value of the function f(x)={2*sin(x), for x>0 and 6-x, for x<=0} for a real argument.

: IF24 ( F: X -> F{X} )
    FDUP 0E FSWAP F<\F: X -> X 0<X
    IF FSIN 2E F* \ if 0<X is true, then F: X -> 2*sin(X)
    ELSE 6E FSWAP F- THEN \ otherwise, F: X -> 6-X
;
0E IF24 F.
6.0000000 Ok
1570796E-6 IF24 F.
2.0000000 Ok

Example 25. Similar to the previous case, but we work with integers. If {X>2} or {X<-2}, then multiply by two, otherwise by minus three.

: IF25 ( X -> F{X} )
    DUP DUP 2 > \ X -> X X X>2
    SWAP -2 < OR \ X X X>2 -> X {X>2}OR{X<-2}
    IF 2 ELSE -3 THEN *
;
-4 IF25 .
-8 Ok
4 IF25.
8 Ok
-1 IF25 .
3 Ok
1 IF25.
-3 Ok
0 IF25 .
0 Ok

Example 26. We work with real numbers again. First, consider the positive semi-axis: X>0 (second line). There can be two cases: the first 0<X<2 (check in the third line, and in the fourth we square the argument to obtain the value of the function), the second - otherwise (fifth line, replace the argument with the number “4”), that is, when X>=2. Having gone through all the options for positive X, it remains to consider (X<=0), the option otherwise (sixth line), here we change the sign of the argument to the opposite.

: IF26 ( F: X ->)
    FDUP 0E FSWAP F<    \ F: X -> X 0<X  - если X>0
    IF FDUP 2E F<       \ F: X -> X X<2, - если 0<X<2
    IF FDUP F*          \ F: X -> X*X
    ELSE FDROP 4E THEN  \ иначе F: 4
    ELSE FNEGATE THEN   \ если {0<X} – ложь, то есть X<=0
;
-1E IF26 F.
1.0000000  Ok
1E IF26 F.
1.0000000  Ok
15E-1 IF26 F.
2.2500000  Ok
3E1 IF26 F.
4.0000000  Ok

If this selection of options is not clear to you, then we will present a more traditional method. We use previously defined words:

: F> ( FA FB -> FA>FB ) FSWAP F< ;
: F>= ( FA FB -> FA>=FB ) FOVER FOVER F> F= OR ;
: F<= ( FA FB -> FA<=FB ) FOVER FOVER F< F= OR ;
: F<> ( FA FB -> FA<>FB )  F= 0= ;                              
: F!= ( FA FB -> FA!=FB ) F= 0= ;
: IF26 ( F: X ->)
    FDUP 0E F<=                      \ F: X -> X X<=0
    IF FNEGATE EXIT THEN             \ F: X -> -X, при  X<=0
    FDUP FDUP 0E F> FSWAP 2E F< AND  \ F: X -> X 0<X<2
    IF FDUP F* ELSE                  \ F: X -> X**2, при 0<X<2
    FDROP 4E THEN                    \ F: X -> 4, иначе
;


Although not all of the words given were used in the example, it will be useful to add them to your file, saving them with the “.F” extension; opening it, the Fort system will already have these tools in its dictionary. And you don't have to do the copy-and-paste routine.

Example 27. In this example, the only difficult thing is the condition, which means that if the integer part of the number is even (including zero), then we print one, if it is odd, minus one, and if the number is negative, then we display zero. Note that in stack notation, the input parameter X is on the real number stack (denoted by "F:"), and the result is on the integer stack (I:). The only reason why this is important is so that you do not get confused and do not try to add them in other examples, or carry out some other joint manipulations, which will inevitably lead to incorrect results, not necessarily with an error message displayed on the screen.

: IF27 ( F: X -> I: {0|1|-1} )  \ здесь фигурные скобки означают множество, 0,1 или -1
    FDUP F0<                    \ если число F в вещественном стеке <0,
    IF 0 EXIT THEN              \ то оставляем «0»
    F>D D>S                     \ иначе превращаем в целое и работаем с обычным стеком, для целых чисел
    2 MOD                       \ если остаток при делении на 2 равен 1, что трактуется как истина
    IF -1                       \ оставляем -1
    ELSE 1 THEN                 \ иначе 1
;
1.9990E IF27 .
-1  Ok
2.9990E IF27 .
1  Ok
0E IF27 .
1  Ok
-1.9990E IF27 .
0  Ok
-2.9990E IF27 .
0  Ok

Example 28. Using the year number, determine the number of days in a year. Essentially, you need to determine whether the year is a leap year (and print 366 if true), if not, print 365.

: IF28 ( Y -> {365|366} )  \ Y – год, выводим 365 (обычный) или 366 (високосный)
    DUP 4 MOD              \ Если остаток от деления на 4 не НОЛЬ, что трактуется как
    IF DROP 365 EXIT THEN  \ истина, оставляем 365 и выходим
    DUP 100 MOD 0 =        \ Y -> Y {Y MOD 100}=0
    SWAP 400 MOD AND       \ Y {Y MOD 100}=0 -> {Y MOD 100}=0&{Y MOD 1000}
    IF 365 EXIT THEN       \ не високосный, если делится на 100 и не делится на 1000
    366                    \ иначе високосный
;
300 IF28
365  Ok
1300 IF28
365  Ok
1900 IF28
365  Ok
1200 IF28
366  Ok
2000 IF28
366  Ok

Example 29. For a given integer, print a description string of the form: (sign) (parity). We duplicate the top of the stack and compare it with zero (second line), if true we display “Zero” and complete the work of the word, otherwise we duplicate it again and check for negativity, as a result we will receive on the screen the message either “Negative” (if true) or "Positive" (otherwise). In the fourth line, divide by two and use the remainder to determine the parity of the original number.

 : IF29 ( N -> )
    DUP 0 = IF ." Ноль" DROP EXIT THEN  \ N=0
    DUP 0 <                             \ N -> N N<0
    IF ." Отрицательное " ELSE ." Положительное " THEN
    2 MOD                               \ N -> {N MOD 2}
    IF ." нечетное число" ELSE ." четное число" THEN
;
-3 IF29
Отрицательное нечетное число Ok
-2 IF29
Отрицательное четное число Ok
-1 IF29
Отрицательное нечетное число Ok
0 IF29
Ноль Ok
1 IF29
Положительное нечетное число Ok
2 IF29
Положительное четное число Ok
3 IF29
Положительное нечетное число Ok

Example 30. It is necessary to display in the description the parity of a number and its significance (the number of its digits). Input number in the range 1 -999. Not much different from the previous one, we determine parity in the same way. Next, by dividing by “100” according to the quotient (if it is greater than zero), we find out whether this number is three-digit; if true, then the problem is solved, otherwise we check for two-digitity; if this is also false, we conclude that the number is single-digit.

: IF30 ( N -> )
    DUP 2 MOD                               \ N -> N {N MOD 2}
    IF ." Нечетное " ELSE ." Четное " THEN  \ Если {N MOD 2}=1, «Нечетное», иначе «Четное»
    DUP 100 /                               \ Если Целая_часть{N/100}>0, то трехзначное
    IF ." трехзначное число " DROP EXIT THEN
    10 /                                    \ Если Целая_часть{N/10}>0, то двузначное
    IF ." двузначное число " EXIT THEN
    ." однозначное число "                  \ иначе однозначное
;
5 IF30
Нечетное однозначное число  Ok
16 IF30
Четное двузначное число  Ok
355 IF30
Нечетное трехзначное число  Ok
998 IF30
Четное трехзначное число  Ok