
Полная версия:
Язык программирования Форт (Forth). Решение задач по программированию. Версия 2.
1E-1 FA F! 2E-1 FB F! 3E-1 FC F! B24 \ FA=0.1 FB=0.2 FC=0.3
FA F@ F. FB F@ F. FC F@ F. \ FA=0.2 FB=0.3 FC=0.1
0.2000000 0.3000000 0.1000000 Ok
Пример 25. Вычислить значение функции, если дан аргумент. Опустим целочисленный вариант, его можно написать по аналогии самостоятельно.
: B25 ( X -> F[X] ) \ F(X)=3*X^6-6*x^2-7
F**2 \ X -> X^2
FDUP -6E F* \ X^2 -> X^2 -6*X^2
–7E F+ \ X^2 {-6*X^2} -> X^2 {-6*X^2-7}
FSWAP \ X^2 {-6*X^2-7} -> {-6*X^2-7} X^2
3E F** \ {-6*X^2-7} X^2 -> {-6*X^2-7} {X^2}^3=X^6
3E F* F+ \ {-6*X^2-7}+{3*X^6}
;
1E B25 F.
–10.000000 Ok \ F(1)=-10
1E-3 B25 F.
–7.0000060 Ok \ F(0.001)=– 7.0000060
А вот при аргументе равным нулю выдает ошибку (возведение нуля в степень):
0E B25 F.
EXCEPTION! CODE:C0000090 ADDRESS:0055384E WORD:F**
USER DATA: 007005BC THREAD ID: 00002120 HANDLER: 0019EF98
STACK: (0) 5BF752DB 00328000 76F066DD 0019FFDC 74C30400 00328000 [74C30419]
RETURN STACK:
0019EF84 : 0056DC53 B25
…………………………………………………………
0019EFB4 : 0056BC66 (INIT)
END OF EXCEPTION REPORT
S" 0E >FLOAT DROP B25 F.
^ 0xC0000090L FLOAT_INVALID_OPERATION
Но во второй раз у меня выдал другой ответ:
0E B25 F.
infinity Ok
После этого лучше перезапустить систему или заново подключить библиотеки работы с вещественными числами, иначе он их не распознает:
1E B25 F.
1E B25 F.
^ -2003 WORD OR FILE NOT FOUND
0E B25 F.
0E B25 F.
^ -2003 WORD OR FILE NOT FOUND
1E-3 B25 F.
1E-3 B25 F.
^ -2003 WORD OR FILE NOT FOUND
После замены кода «F**2» на «FDUP F*» и «3E F**» на «FDUP FDUP F* F*» проблема исчезает.
: B25 ( X -> F[X] ) \ F(X)=3*X^6-6*x^2-7
FDUP F* \ X -> X^2
FDUP -6E F* \ X^2 -> X^2 -6*X^2
–7E F+ \ X^2 {-6*X^2} -> X^2 {-6*X^2-7}
FSWAP \ X^2 {-6*X^2-7} -> {-6*X^2-7} X^2
FDUP FDUP F* F* \ {-6*X^2-7} X^2 -> {-6*X^2-7} {X^2}^3=X^6
3E F* F+ \ {-6*X^2-7}+{3*X^6}
;
0E B25 F.
–7.0000000 Ok
Пример 26. Брат близнец предыдущего. Разница в формуле. Так же рассмотрим только вещественный аргумент.
: B26 ( X -> F[X] ) \ F[X]=4*{X-3}^6-7*{X-3}^3+2
3E F- \ X -> X-3
3E F** \ X-3 -> (X-3)^3
FDUP -7E F* \ (X-3)^3 -> (X-3)^3 {-7*(X-3)^3}
FSWAP F**2 \ (X-3)^3 {-7*(X-3)^3} -> {-7*(X-3)^3} [(X-3)^3]^2
4E F* \ {-7*(X-3)^3} (X-3)^6 -> {-7*(X-3)^3} 4*(X-3)^6
2E F+ F+ \ {-7*(X-3)^3} 4*(X-3)^6 -> {-7*(X-3)^3}+4*(X-3)^6+2
;
4E B26 F.
–1.0000000 Ok
3E B26 F.
2.0000000 Ok
Здесь ошибки пи возведении нуля в степень не выдал, но при вводе кода «0E 3E F** F.» по-прежнему выдает ошибку. Будьте осторожны при возведении в степень, это опасная операция, вызывающая много ошибок.
Пример 27. В Форте дополнительная переменная здесь и не понадобится. Для тех, кто любит все выполнять строго по инструкции – задача самостоятельно переписать код.
: B27 ( A -> A^2 A^4 A^8)
DUP * \ A -> A^2
DUP DUP * \ A^2 -> A^2 A^4
DUP DUP * \ A^2 A^4 -> A^2 A^4 A^8
;
Примеры работы слова:
2 B27
Ok ( 4 16 256 )
3 B27
Ok ( 9 81 6561 )
Без комментариев.
С вещественным аргументом задача ничуть не сложнее. Заменяем все операторы на соответствующие, просто добавив «F».
: B27 ( A -> A^2 A^4 A^8 )
FDUP F* \ A -> A^2
FDUP FDUP F* \ A^2 -> A^2 A^4
FDUP FDUP F* \ A^2 A^4 -> A^2 A^4 A^8
;
2E B27 F. F. F.
256.00000 16.000000 4.0000000 Ok \ Порядок печати обратный
3E B27 F. F. F.
6561.0000 81.000000 9.0000000 Ok
Пример 28. Похож на предыдущую задачу и чуть посложнее.
: B28 ( A -> A^2 A^3 A^5 A^10 A^15 )
DUP DUP * \ A -> A A^2
SWAP OVER * \ A A^2 -> A^2 A^3
OVER OVER * \ A^2 A^3 -> A^2 A^3 A^5
DUP DUP * \ A^2 A^3 A^5 -> A^2 A^3 A^5 A^10
OVER OVER * \ A^2 A^3 A^5 A^10 -> A^2 A^3 A^5 A^10 A^15
;
2 B28
Ok ( 4 8 32 1024 32768 )
3 B28
Ok ( 9 27 243 59049 14348907 )
Не забывайте, что степенная функция растет очень быстро и при большом основании быстро произойдет переполнение, в результате ответ будет некорректным. Так, например, при A=10, уже 10-ая степень вычисляется не правильно.
10 B28
Ok ( 100 1000 100000 1410065408 2764472320(-1530494976) )
Для вещественного аргумента.
: B28 ( A -> A^2 A^3 A^5 A^10 A^15)
FDUP FDUP F* \ A -> A A^2
FSWAP FOVER F* \ A A^2 -> A^2 A^3
FOVER FOVER F* \ A^2 A^3 -> A^2 A^3 A^5
FDUP FDUP F* \ A^2 A^3 A^5 -> A^2 A^3 A^5 A^10
FOVER FOVER F* \ A^2 A^3 A^5 A^10 -> A^2 A^3 A^5 A^10 A^15
;
2E B28 F. F. F. F. F.
32768.000 1024.0000 32.000000 8.0000000 4.0000000 Ok \ опять обратный порядок при печати
3E B28 F. F. F. F. F.
14348907. 59049.000 243.00000 27.000000 9.0000000 Ok
Очевидно слово работает корректно.
Пример 29. Перевести градусы в радианы.
Целочисленный вариант будет в 100 раз больше, поэтому его код не приводится. При необходимости можно его получить из кода для вещественного аргумента.
: B29 ( A{DEG} -> X{RAD} ) \ X=A*Pi/180
314E-2 F* \ A -> 3.14*A
180E F/ \ 3.14*A -> 3.14*A/180
;
Нижеприведенные тесты корректны.
90E B29 F.
1.5700000 Ok
360E B29 F.
6.2800000 Ok
Для повышения точности, самостоятельно перепишите слово «B29» используя слово «FPI».
Пример 30. Обратная к предыдущему задача перевода из радиан в градусы.
: B30 ( A{RAD} -> X{DEG} ) \ 180*A/Pi
180E F* \ A -> 180*A
314E-2 F/ \ 180*A -> 180*A/Pi
;
Тесты слова B30.
314E-2 B30 F.
180.00000 Ok
628E-2 B30 F.
360.00000 Ok
Как и в предыдущем случае, перепишите для увеличения точности.
Небольшие хитрости для оптимизации работы с системой программирования SP-forth.
Если вы планируете использовать последние два слова в своей работе, то можно их назвать по практичнее и добавить в свой файл Форт-расширения.
Например, RAD>DEG и DEG>RAD (знак «>» означает перевести, перенести в зависимости от контекста использования).
Пример содержания такого файла:
\ Подключение библиотеки для работы с вещественными числами
S" lib\include\float2.f" INCLUDED
VARIABLE A VARIABLE B VARIABLE C \ Часто используемые переменные
FVARIABLE FA FVARIABLE FB FVARIABLE FC
: DEG>RAD ( A{DEG} -> X{RAD} ) \ X=A*Pi/180 – градусы в радианы
314E-2 F* \ A -> 3.14*A
180E F/ \ 3.14*A -> 3.14*A/180
;
: RAD>DEG ( A{RAD} -> X{DEG} ) \ 180*A/Pi – радианы в градусы
180E F* \ A -> 180*A
314E-2 F/ \ 180*A -> 180*A/Pi
;
: MIDDLE_ARITHMETIC ( A B -> [A+B]/2 ) \ среднее арифметическое
F+ 2E F/ ;
: MIDDLE_GEOMETRIC ( A B -> SQRT[A*B] ) \ среднее геометрическое
F* FSQRT ;
: R2D ( X1 Y1 X2 Y2-> R ) \ R= Квадратный_Корень((X2-X1)^2+(Y2-Y1)^2)
\ вычисление расстояния между двумя точками через их координаты на плоскости
FROT F- FDUP F* \ X1 Y1 X2 Y2-> X1 X2 (Y2-Y1)^2
FSWAP FROT F- FDUP F* \ X1 X2 (Y2-Y1)^2 -> (Y2-Y1)^2 (X2-X1)^2
F+ FSQRT \ (Y2-Y1)^2 (X2-X1)^2 -> R
;
Назовите файл как вам нравится, но обязательно с расширением «.F», тогда его можно будет запустить и он откроется в SP-Forth, при условии, что он у вас установлен. Тогда вам не придется каждый раз выполнять рутинные задачи, которые вы включите в этот файл.
Чтобы упростить интерфейс взаимодействия с написанными словами, например, вывод результатов расчета для слов со множеством выходных параметров, можно применить следующую методику, описанную далее.
Рассмотрим пример №28.
2E B28 F. F. F. F. F.
Здесь «B28 F. F. F. F. F.» заменяем на слово
: B28. ( A^2 A^3 A^5 A^10 A^15 -> ) B28 F. F. F. F. F. ;
Такой вариант предпочтительный не только из-за упрощения, но и исходя из того, что вы со временем забудете, как работает слово, а разбираться в работе слове каждый раз не разумно, да и зачем перегружать мозг бесполезными мелочами? Оператор «.» – точка в Форте всегда связана с печатью на экран, поэтому «Name.» – логично означает печать результатов слова «Name». Только не забудьте написать соответствующее слово перед ее выполнением, автоматически слова в Форте не пишутся. Так же можно включать словесное описание результатов, например,
: B28. ( A^2 A^3 A^5 A^10 A^15 -> ) B28
.” A^2= “ F. CR \ CR – это оператор перевода на новую строку
.” A^3= “ F. CR
.” A^5= “ F. CR
.” A^10= “ F. CR
.” A^15= “ F. CR
;
Окончательно вызов слова B28 будет выглядеть, с учетом упрощения, так:
2E B28.
Так мы разделяем алгоритм работы слова с его примитивным интерфейсом вывода результатов. В таком случае при необходимости что-то доработать, одно не помешает другому и, разумеется, код становится более лаконичным и понятным.
BEGIN 31-40
Пример 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 F* 9E 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) –> |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
Код «-1E F*» можно заменить на «FNEGATE», который лучше, но для начала может быть менее наглядным.
Пример 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 X1 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 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 .” D=“ 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 новых вещественных переменных, чтобы не путаться в коэффициентах. Первая строка – стандартное описание логики работы слова. Вторая – сохранение значений на стеке в соответствующие переменные. На вершине находится значение последней введённой, а значит его первым и сохраняем. Вычисление D. Дублируем D, так как он нам понадобится два раза, также мы его копируем и печатаем для проверки промежуточных вычислений. После отладки код «.” D=“ FDUP F. CR» можно удалять. Вычисление X Вычисление 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). Видим, что слово работает корректно. Integer 1-30 Теперь мы решаем новую группу заданий с исключительно целочисленными параметрами. Все задания мы будем нумеровать с префиксом 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 Теоретически, последним штрихом, будет оформление вывода в отдельное слово, как говорилось ранее в предыдущей группе задач, по схеме: