Пример 31. Перевести температуру в Фаренгейтах в градусы Цельсия. Сперва для целых значений температуры.

: B31 ( TF-> TC ) \ TC=(TF-32)*5/9
    32 – 5 * 9 /
;
32 B31             \ 32 град Фаренгейта = 0 град Цельсия, 32-32=0, 0*5/9=0
 Ok ( 0 )
35 B31             \ 35 град Фаренгейта = 1 град Цельсия (35-32)=3, 3*5=15, 15/9=1 – целая часть
 Ok ( 0 1 )
40 B31             \ 40 град Фаренгейта = 4 град Цельсия (40-32)=8, 8*5=40, 40/9=4 – целая часть
 Ok ( 0 1 4 )

С незначительными изменениями мы сможем переписать код для вещественных значений температуры.

: B31 ( TF-> TC ) \ TC=(TF-32)*5/9
    32E F-
    5E 9E F/ F*
;
32E B31 F.         \ как и в первом варианте, только результат в вещественном формате
0.0000000  Ok
321E-1 B31 F.
0.0555555  Ok

Пример 32. Обратная к предыдущему примеру задача. Перевести температуру из Цельсия в Фаренгейты.

: B32 ( TC -> TF ) \ TF= TC*9/5+32
    9 * 5 / 32 + ;
0 B32               \ 0 град Цельсия = 32 град Фаренгейта
 Ok ( 32 )
-18 B32
 Ok ( 32 0 )        \ -18 град Цельсия = 0 град Фаренгейта

Для вещественного аргумента.

: B32 ( TC -> TF ) \ TF= TC*9/5+32
    9E F* 5E F/ 32E F+ ;
0E B32 F.           \ 0 град Цельсия = 32 град Фаренгейта
32.000000  Ok
-18E B32 F.         \ -18 град Цельсия = -0,4 град Фаренгейта
-0.4000000  Ok

Ноль градусов по Цельсию по-прежнему 32 градусов Фаренгейта, единственное отличие – результат вещественное число, а вот при T=-18 остаток уже не отбрасывается, как в первом случае, и ответ получается точный.

Пример 33. Детская задача. Цена 1 кг конфет обозначим через C1, а Y кг соответственно CY, тогда легко вычислить C1=A/X и CY=C1*Y, а дано X кг за A рублей и количество Y кг, цену которого нужно вычислить.

:  B33 ( X A Y -> C1 CY ) \ C1=A/X CY=C1*Y
    SWAP ROT /             \ X A Y -> Y A/X=C1
    SWAP OVER *            \ Y C1 -> C1 Y*C1= CY
;
3 9 10 B33                 \ 3 кг стоит 9 р, т. е. 3р за 1 кг, а 10 кг будут стоить 3*10=30 р
 Ok ( 3 30 )

Вы можете самостоятельно потренироваться на современных ценах различных товаров.

А теперь для дробных цен.

:  B33 ( X A Y -> C1 CY ) \ C1=A/X CY=C1*Y
    FSWAP FROT F/          \ X A Y -> Y A/X=C1
    FSWAP FOVER F*         \ Y C1 -> C1 Y*C1= CY
;
3E 9E 10E B33 F. F.
30.000000 3.0000000  Ok

Проверили на тех же данных. И снова не забываем об обратном порядке при печати со стека, не важно с какого (целочисленного или вещественного). Чтобы в начале вывести цену за 1 кг, можно использовать слово FSWAP перед «F.» или переписать строчку

FSWAP FOVER F*     \ Y C1 -> C1 Y*C1= CY

таким образом

FDUP F. F*         \ Y C1 -> Y*C1= CY

Но в этом случае код не универсален, а значит менее предпочтителен. Желательно вычисление и печать разграничить, чтобы можно было, написанную функцию использовать в различных местах и ситуациях, а не «изобретать велосипед» каждый раз.

Пример 34. Продолжение детских задачек.

: B34 ( X A Y B -> CX CY CX/CY ) \ CX=A/X CY=B/Y CX/CY
    SWAP /                        \ X A Y B -> X A B/Y=CY
    SWAP ROT /                    \ X A CY -> CY A/X=CX
    SWAP 2DUP /                   \ CY CX  -> CX CY CX/CY
;
5 30 5 15 B34
 Ok ( 6 3 2 )

Цена шоколадных конфет равна 30/5= 6 р/кг, ирисок 15/5=3 р/кг, и соответственно шоколадные конфеты дороже ирисок в 6/3=2 раза. Перепишем для вещественного аргумента, чтобы не терять точность для «неудобных данных».

: B34 ( X A Y B -> CX CY CX/CY ) \ CX=A/X CY=B/Y CX/CY
    FSWAP F/                      \ X A Y B -> X A B/Y=CY
    FSWAP FROT F/                 \ X A CY -> CY A/X=CX
    FSWAP FOVER FOVER F/          \ CY CX  -> CX CY CX/CY
;
5E 30E 5E 15E B34 F. F. F.
2.0000000 3.0000000 6.0000000  Ok

И снова обратный порядок, результат идентичен первому варианту с целыми аргументами.

Пример 35. Детская задачка на движение лодки в стоячей и движущейся воде.

VARIABLE T2
: B35 ( V U T1 T2 -> S )  \ S=S1+S2, S1=V*T1, S2=(V-U)*T2
    T2 !                  \ V U T1 T2 -> V U T1
    ROT DUP ROT *         \ V U T1 -> U V V*T1=S1
    SWAP ROT -            \ U V S1 -> S1 V-U
    T2 @ *                \ S1 V-U -> S1 [V-U]*T2=S2
    +                     \ S=S1+S1
;

Манипуляции на стеке неоправданно усложняются с четырьмя и более элементами, поэтому мы сохраним значение T2 в одноименной переменной. Сперва мы вычисляем путь S1 в стоячей воде, затем считывая время T2 из переменной - путь S2 и соответственно ему скорость. Ответ есть сумма двух путей. Проверим написанное слово.

10 5 1 1 B35
 Ok ( 15 )

1 час в стоячей воде со скоростью 10 – это путь равный 10*1=10 и такое же время со скоростью 10-5=5. В итоге общий путь 10+5=15.

С вещественными данными слово будет иметь вид:

FVARIABLE FT2
: B35 ( V U T1 T2 -> S )  \ S=S1+S2, S1=V*T1, S2=(V-U)*T2
    FT2 F!                \ V U T1 T2 -> V U T1
    FROT FDUP FROT F*     \ V U T1 -> U V V*T1=S1
    FSWAP FROT F-         \ U V S1 -> S1 V-U
    FT2 F@ F*             \ S1 V-U -> S1 [V-U]*T2=S2
    F+                    \ S=S1+S1
;
10E 5E 1E 1E B35 F.
15.000000  Ok

На предыдущих данных, как и положено, дает тот же результат, но с типом float.

Пример 36. Без комментариев, сразу приведем решение.

: B36 ( V1 V2 S0 T -> S ) \ S=S0+(V1+V2)*T
    2SWAP + * +            \ V1 V2 S0 T -> S0+T*(V1+V2)
;
3 5 100 2 B36
 Ok ( 116 )
\ 3+5=8, 8*2=16, 16+100=116.
FVARIABLE FS0
: B36 ( V1 V2 S0 T -> S )  \ S=S0+(V1+V2)*T
    FSWAP FS0 F!           \ V1 V2 S0 T -> V1 V2 T
    FROT FROT F+ F*        \ V1 V2 T -> T*(V1+V2)
    FS0 F@ F+              \ T*(V1+V2)+S0
;
3E 5E 100E 2E B36 F.
116.00000  Ok

По предыдущему опыту мы вводим новую переменную, чтобы уменьшить количество элементов на вещественном стеке. Ответ совпадает с первым вариантом, только вещественного формата, что подтверждает корректность теста.

Пример 37. Абсолютно аналогичен предыдущему примеру, за исключением, двух моментов – сумма заменяется разностью, и разность помещается в модуль.

: B37 ( V1 V2 S0 T -> S ) \ S=|S0-T*(V1+V2)|
    2SWAP + * - ABS        \ V1 V2 S0 T -> |S0-T*(V1+V2)|
;
3 5 100 2 B37
 Ok ( 84 )
\ 3+5=8, 8*2=16, |100-16|=84. Проверим как работает модуль, для этого положим S0=10.
3 5 10 2 B37
 Ok ( 6 )
\ 3+5=8, 8*2=16, |10-16|=6. Все верно, код работает корректно.
FVARIABLE FS0
: B37 ( V1 V2 S0 T -> S )  \ S=|T*(V1+V2)-S0|
    FSWAP FS0 F!           \ V1 V2 S0 T -> V1 V2 T
    FROT FROT F+ F*        \ V1 V2 T -> T*(V1+V2)
    FS0 F@ F- FABS         \ |T*(V1+V2)-S0|
;
3E 5E 100E 2E B37 F.
84.000000  Ok
3E 5E 10E 2E B37 F.
6.0000000  Ok

Для вещественного аргумента мы получили тот же ответы в соответствующем формате.

Пример 38. Тривиальная школьная задача, которую мы решим сразу в вещественной форме. При необходимости, желающие смогут самостоятельно написать код для целого аргумента.

: B38 ( A B -> X )  \ X=-B/A
    -1E F* FSWAP F/  \ A B -> -B/A
;
10E 3E B38 F.
-0.3000000  Ok

Пример 39. Решение квадратного уравнения. Обратите внимание, что в названии вещественных переменных опущены префиксы «F», так как в этих словах используются переменные только одного типа. Если вас это запутывает, то вы легко можете добавить их. Если все слова вы добавляете в один файл, то эта проблема будет актуальной, так же вы можете в названиях слов добавлять префикс I (Integer), для функций с целочисленными аргументами и F, с вещественными, иначе SP-Forth, будет выводить сообщения «B39 isn't unique ()», что не является ошибкой, но предупреждением, что при вызове слова будет вызываться только определенное последней слово. Могут возникнуть скрытые ошибки. Так если вы определили целочисленное слово, затем вещественное и после выполняете попеременно слова для разных аргументов, то как было сказано будет вызвано исключительно последняя реализация, что неизбежно приведет к ошибке, связанное с тем что слова будут работать с аргументами в разных стеках, в итоге, будет либо нехватка аргументов, либо порча других данных не предназначенных для этого. Изменив названия при помощи префиксов, вы избавитесь от этих проблем.

FVARIABLE A
: B39 ( A B C -> X1 X2)    \ X1,X2=(-B+-SQRT(D))/2*A
    FROT FDUP A F! F*      \ A B C -> B C*A
    FOVER FDUP F*          \ B C*A -> B C*A B^2
    FSWAP 4E F* F- FSQRT   \ B C*A B^2 -> B SQRT{B^2-4*C*A=D}
    FSWAP -1E F* FSWAP     \ B D^0.5 -> -B D^0.5
    FOVER FOVER F+ A F@    \ -B D^0.5 -> -B D^0.5 –B+D^0.5 A
    2E F* F/               \ -B D^0.5 –B+D^0.5 A  -> -B D^0.5 [–B+D^0.5]/[A*2]=X1
    FROT FROT F- A F@      \ -B D^0.5 X1 -> X1 –B-D^0.5 A
    2E F* F/               \ X1 –B-D^0.5 A -> X1 [–B-D^0.5]/[A*2]=X2
    FOVER FOVER F<         \ X1 X2 X1<X2?
    IF FSWAP THEN
;
1E 4E 1E B39 F. F.
-3.7320508 -0.2679491  Ok

X^2+4*X+1=0, D=4^2-4*1*1=16-4=12. X1,X2=(-4+-12^0.5)/(2*1)=-2+-SQRT(3)

X1=-2- 1,732= -3,732, X2=-2+1,732=-0,268.

А вот случай, когда D=0

1E 2E 1E B39 F. F.
-1.0000000 -1.0000000  Ok

Если манипуляции со стеком вам не понятны, то мы можем переписать последнее слово с использованием 3-переменных A, B, C, по классической схеме.

FVARIABLE A
FVARIABLE B
FVARIABLE C
: B39 ( A B C -> X1 X2)             \ X1,X2=(-B+-SQRT(D))/2*A, X1,X2
    C F! B F! A F!                  \ A B C ->
    B F@ FDUP -1E F* FSWAP FDUP F*  \ -B B^2
    A F@ C F@ F* -4E F* F+ FSQRT    \ -B B^2 -> -B {B^2+A*C*(-4)}^0.5=D^0.5
    FOVER FOVER F+                  \ -B D^0.5 -> -B D^0.5 -B+D^0.5
    A F@ 2E F* F/                   \ -B D^0.5 -B+D^0.5-> -B D^0.5 [-B+D^0.5]/[A*2]=X1
    FROT FROT F-                    \ -B D^0.5 X1 -> X1 -B-D^0.5
    A F@ 2E F* F/                   \ X1 [-B-D^0.5]/[A*2]=X2
    FOVER FOVER F<                  \ X1 X2 X1<X2?
    IF FSWAP THEN
;
1E 4E 1E B39 F. F.
-3.7320508 -0.2679491  Ok

Ответ как в первом случае. Какой проще и понятнее решайте сами.

Пример 40. Задача решения системы из двух линейных уравнений с двумя неизвестными. Пропустим вариант с целочисленными аргументами и перейдем к общему случаю.

FVARIABLE A1 FVARIABLE B1 FVARIABLE C1
FVARIABLE A2 FVARIABLE B2 FVARIABLE C2
: B40 ( A1 B1 C1 A2 B2 C2 -> X Y )             \ X=(C1*B2-C2*B1)/D, Y=(A1*C2-A2*C1)/D, D=A1*B2-A2*B1
    C2 F! B2 F! A2 F! C1 F! B1 F! A1 F!        \ A1 B1 C1 A2 B2 C2 ->
    A1 F@ B2 F@ F* A2 F@ B1 F@ F* F-           \ -> A1*B2-A2*B1=D
    FDUP S” D= “ TYPE FDUP F. CR               \ D -> D D
    C1 F@ B2 F@ F* C2 F@ B1 F@ F* F- FSWAP F/  \ D D -> D (C1*B2-C2*B1)/D=X
    A1 F@ C2 F@ F* A2 F@ C1 F@ F* F- FROT F/   \ D X -> X (A1*C2-A2*C1)/D=Y
;

Здесь мы создали 6 новых вещественных переменных, чтобы не запутаться в логике коэффициентов.

  1. Первая строка - стандартное описание логики работы слова.
  2. Вторая - сохранение значений на стеке в соответствующие переменные. На вершине находится значение последней введённой, а значит его первым и сохраняем.
  3. Вычисление D.
  4. Дублируем D, так как он нам понадобится два раза, также мы его копируем и печатаем для проверки промежуточных вычислений. После отладки код «S” D= “ TYPE FDUP F. CR» можно удалять.
  5. Вычисление X
  6. Вычисление Y

Проверим корректность работы слова на следующих данных

   3x+5y=7    (A1=3    B1=5    C1=7)

   6x+y=4      (A2=6    B2=1    C2=4)

3E 5E 7E 6E 1E 4E B40 F. F.
D= -27.000000
1.1111111 0.4814814  Ok

D=3*1-6*5=3-30=-27, совпадает с результатом выданном словом. X=(7*1-4*5)/(-27)=13/27=(0,481). Y=(3*4-6*7)/(-27)=(12-42)/(-27)=30/27=1,(1). Видим, что слово работает корректно.