Перейти к содержанию

Решение задач по программированию на языке Форт (Forth). Версия 3

Автор:

5,0 10+ оценок читателей Рунета
Категория
компьютерная справочная литература
Год издания
Издательство
Автор
Возрастное ограничение
12+
Обновлено
25.09.2026

Аннотация

Программирование – это легко и просто! Не верите?! Правильно делаете, проверяйте сами, насколько это может быть легко, если правильно выбрать язык и среду. Данный курс программирования основан на решении практических задач.

Читать «Решение задач по программированию на языке Форт (Forth). Версия 3» — Arsen Gonian онлайн

Страница 3 из 7

FOVER FOVER F+ \ |A| |B|-> |A| |B| (|A|+|B|)=(+)

FROT FROT FOVER FOVER F- \ |A| |B| (+) -> (+) |A| |B| (|A|-|B|)=(-)

FROT FROT FOVER FOVER F* \ (+) |A| |B| (-) -> (+) (-) |A| |B| (|A|*|B|)=(*)

FROT FROT F/ \ (+) (-) |A| |B| (*)-> (+) (-) (*) (|A|/|B|)=(*)

;


Рис 22

В комментариях (скобках) соответствующие сумма, разность, произведение и частное взяты в фигурные скобки для визуального выделения элементов на стеке. Обычные скобки в данном случае применять нельзя, так как они обозначают комментарий и являются зарезервированными словами Форта и системы программирования SP-Forth в частности.

Тесты на корректность работы написанных слов произведите самостоятельно.

Пример 12. Вычислить гипотенузу и периметр прямоугольного треугольника по его катетам. Так как мы имеем дело с квадратным корнем, сразу приведем код для случая с вещественным аргументом.

: B12 ( A B -> C P ) \ C=Квадратный_Корень(A^2+B^2) P=A+B+C

FOVER FDUP F* \ A B -> A B A^2

FOVER FDUP F* \ A B A^2 -> A B A^2 B^2

F+ FSQRT \ A B A^2 B^2 -> A B Квадратный_Корень(A^2+B^2)=C

FROT FROT F+ \ A B C -> C A+B

FOVER F+ \ C A+B -> C A+B+C=P

;

Проверим на прямоугольном треугольнике с катетами 3 и 5:

3E 4E B12 F. F. \ вызываем нашу подпрограмму и печатаем результат

12.000000 5.0000000 Ok

3^2+4^2=25. Квадратный корень из 25=5. 5+3+4=12– что является истиной. В данном случае специально подобрана Пифагорова тройка, для простоты проверки. Проверим общий случай:

3E 5E B12 F. F.

13.830952 5.8309519 Ok

Можете самостоятельно проверить истинность теста.


Рис 23

Пример 13. Найти площади двух кругов (с общим центром) и кольца между ними. Даны радиусы R1 и R2, причем R1 > R2. Как и ранее сперва напишем слово для целочисленных чисел. Если не совсем понятно почему я не пишу сразу универсальный вариант для вещественных данных, то поясняю: отладка в этом случае наиболее проста для сложных слов и для начинающих, так как все данные на стеке видны сразу после их ввода, то получается легко проверить и понять работу кода пошагово вводя команду за командой. Этого преимущества лишены операторы для работы с вещественными числами. После написания слова с целыми аргументами не сложно перевести его код для работы с вещественными и получить результат того же типа.

: B13 ( R1 R2 -> S1 S2 S3) \ S1=Pi*R1^2 S2= Pi*R2^2 S3=S1-S2

SWAP DUP * 314 * \ R1 R2 -> R2 (Pi*R1^2)=S1

SWAP DUP * 314 * \ R2 S1 -> S1 (Pi*R2^2)=S2

2DUP – \ S1 S2 -> S1 S2 (S1-S2)=S3

;

Запустим наше слово на примере двух кругов с радиусами 25 и 15 соответственно.

25 15 B13

Ok ( 196250 70650 125600 )

Выше приведен вариант кода с целочисленными аргументами, причем все 3 площади больше в 100 раз из-за того, что мы приняли Пи равным 314. При необходимости используйте написанное ранее слово «.2». Далее перепишем пример для случая вещественных аргументов.

: B13 ( R1 R2 -> S1 S2 S3) \ S1=Pi*R1^2 S2= Pi*R2^2 S3=S1-S2

FSWAP FDUP F* 314E-2 F* \ R1 R2 -> R2 (Pi*R1^2)=S1

FSWAP FDUP F* 314E-2 F* \ R2 (Pi*R1^2)=S1 -> (Pi*R1^2)=S1 (Pi*R2^2)=S2

FOVER FOVER F- \ S1 S2 -> S1 S2 (S1-S2)=S3

;

Тестирование примера 13:

25E-1 15E-1 B13 F. F. F.

12.560000 7.0650000 19.625000 Ok

S1 = 19,625 = 3.14*2.5^2; S2 = 7,065 = 3.14*1.5^2; S3=S1-S2=12,56=19,625-7,065.

Тестирование прошло успешно. Не забываем про обратный порядок печати со стека. Написанное слово работает правильно, соответственно стековой нотации. Если вам необходим другой порядок вывода, то можете самостоятельно скорректировать слово, добавив код после вызова «B13» и до вывода «F. F. F.». Ранее аналогичные манипуляции со стеком уже совершались. Также в зависимости от того в каком виде вам нужны результаты вывода слова «B13» в первом случае, проведите соответствующую обработку по выводу на экран или напишите слово «B13.». Чтобы отличать обе версии, добавьте к именам «I и F», чтобы получились имена «B13I» и «B13F» и соответствующие им слова для печати результатов «B13I.» и «B13F.»


рис 24

Пример 14. Определить радиус окружности и площадь круга, через ее длину. Сразу составим программку для вещественного аргумента, ибо целочисленное огругление будет давать неприемлемый по качеству результат для малых значений длины окружности.

: B14 ( L -> R S ) \ R=L/(2*Pi) S=Pi*R^2

628e-2 F/ \ L -> R=L/6.28 где 6,28=2*Pi=D

FDUP FDUP F* 314e-2 F* \ R -> R Pi*R^2

;


рис 25

Посчитаем R и S для L=25,37

2537E-2 B14 F. F.

51.244976 4.0398089 Ok

R=25.37/6.28= 4,0398 и S=3,14* 4,0398^2= 51,244. Тест прошел успешно.

Перепишем код с учетом слова «FPI» (значение «Пи» получаемое системой). Наберите «FPI F.», чтобы узнать точное значение получаемое Форт-словом.

: B14 ( L -> R S ) \ R=L/(2*Pi) S=Pi*R^2

FPI 2E F* F/ \ L -> R=L/6.28 где 6,28=2*Pi=D

FDUP FDUP F* FPI F* \ R -> R Pi*R^2

;

2537E-2 B14 F. F.

51.218997 4.0377609 Ok

Сами можете сравнить уточненные результаты, при использовании более точного значения «Пи». Второй вариант не только универсален, но и незаменим для научных расчетов.

Пример 15. Зная площадь круга, вычислить его диаметр и длину.

: B15 ( S -> D L ) \ D=Квадратный_Корень(4*S/Pi) L=Pi*D

4E F* \ S -> 4*S

314E-2 F/ \ 4*S -> 4*S/Pi

FSQRT \ 4*S/Pi -> Квадратный_Корень(4*S/Pi)=D

FDUP 314E-2 F* \ D -> D D*Pi=L

;

Посчитаем диаметр и длину круга площадью равной 12,345.

12345E-3 B15 F. F.

12.452036 3.9656166 Ok

Квадратный корень из (12,345*4/3.14) равно 3,965616, а 3,965616*3,14=12,4520, то ест ь ИСТИНА. Пример довольно простой и нет других причин писать код для целочисленного варианта аргументов. В случае необходимости несложно самостоятельно решить эту задачу.



рис 26

Пример 16. Вычислим расстояние между двумя точками на числовой оси, зная координаты.

: B16 ( X1 X2 -> |X1-X2| )

– ABS \ X1 X2 -> |X1-X2|

;

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

: B16 ( X1 X2 -> |X1-X2| )

F- FABS \ X1 X2 -> |X1-X2|

;


рис 27

31E-1 -12E1 B16 F.

123.10000 Ok \ |3.1-(-120)|=123.1

Пример 17. По трем координатам на числовой оси (X1, X2, X3) вычислить следующие расстояния: |x1-x3|, |x2-x3| и их сумму. Сперва для целых чисел.

: B17 ( X1 X2 X3 -> |x1-x3| |x2-x3| {|x1-x3|+|x2-x3|} )

SWAP OVER \ X1 X2 X3 -> X1 X3 X2 X3

– ABS \ X1 X3 X2 X3 -> X1 X3 |X2-X3|

ROT ROT – ABS SWAP \ X1 X3 |X2-X3| -> | X1-X3| |X2-X3|

2DUP + \ | X1-X3| |X2-X3|-> | X1-X3| |X2-X3| (| X1-X3|+|X2-X3|)

;

Для вещественных.

: B17 ( X1 X2 X3 -> |x1-x3| |x2-x3| {|x1-x3|+|x2-x3|} )

FSWAP FOVER \ X1 X2 X3 -> X1 X3 X2 X3

F- FABS \ X1 X3 X2 X3 -> X1 X3 |X2-X3|

FROT FROT F– FABS FSWAP \ X1 X3 |X2-X3| -> | X1-X3| |X2-X3|

FOVER FOVER F+ \ | X1-X3| |X2-X3|-> | X1-X3| |X2-X3| (| X1-X3|+|X2-X3|)

;

Тест на координатах

–1E1 1E-1 3E2 B17 F. F. F.

609.90000 299.90000 310.00000 Ok

|X1-X3|=|-10-300|=310; |X2-X3|=|0.1-300|=299.9; (|X1-X3|+|X2-X3|)=310+299.9=609.9.


рис 28

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

: B18 ( X1 X2 X3 -> {|x1-x3|*|x2-x3|} )

SWAP OVER \ X1 X2 X3 -> X1 X3 X2 X3

– ABS \ X1 X3 X2 X3 -> X1 X3 |X2-X3|

ROT ROT – ABS * \ X1 X3 |X2-X3| -> {|x1-x3|*|x2-x3|}

;

–5 2 7 B18

Ok ( 60 )

|-5-7|*|2-7|= 12*5=60

Для вещественных чисел.

: B18 ( X1 X2 X3 -> {|x1-x3|*|x2-x3|} )

FSWAP FOVER \ X1 X2 X3 -> X1 X3 X2 X3

F- FABS \ X1 X3 X2 X3 -> X1 X3 |X2-X3|

FROT FROT F– FABS F* \ X1 X3 |X2-X3| -> {|x1-x3|*|x2-x3|}

;

–1E1 2E-1 23E1 B18 F.

55152.000 Ok

|-10-230|*|0.2-230|=240*229.8=55152


рис 29

Пример 19. По координатам противоположенных вершин прямоугольника вычислить его периметр и площадь, стороны параллельны координатным осям.

: B19 ( X1 Y1 X2 Y2 -> P S ) \ P=2*[A+B] S=A*B

ROT – ABS \ X1 Y1 X2 Y2 -> X1 X2 |Y2-Y1|

SWAP ROT – ABS \ X1 X2 |Y2-Y1| -> |Y2-Y1|=A |X2-X1|=B

2DUP + 2* \ A B -> A B 2*(A+B)=P

ROT ROT * \ A B P -> P A*B=S

;

1 3 7 8 B19 . .

30 22 Ok

A=|1-7|=6 B=|3-8|=5. P=2*(A+B)=2*(6+5)=22. S=A*B=6*5=30.

Вариант с вещественными аргументами не сильно отличается от целочисленного.

: B19 ( X1 Y1 X2 Y2 -> P S ) \ P=2*[A+B] S=A*B

FROT F- FABS \ X1 Y1 X2 Y2 -> X1 X2 |Y2-Y1|

FSWAP FROT F– FABS \ X1 X2 |Y2-Y1| -> |Y2-Y1|=A |X2-X1|=B

FOVER FOVER F+ 2E F* \ A B -> A B 2*(A+B)=P

FROT FROT F* \ A B P -> P A*B=S

;

11E-1 15E-1 73E-1 62E-1 B19 F. F.

29.140000 21.800000 Ok

A=|1.5-6.2|=4.7; B=|1.1-7.3|=6.2; P=2*(4.7+6.2)= 21,8; S=A*B=4.7*6.2= 29,14.


рис 30

Пример 20. Вычислить расстояние между двумя точками на плоскости по их координатам. Так как придется извлекать квадратный корень, то вариант с целочисленными координатами пропускаем.

: B20 ( 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

;

11E-1 15E-1 73E-1 62E-1 B20 F.

7.7801028 Ok

A=|1.5-6.2|=4.7; B=|1.1-7.3|=6.2; R= Квадратный_Корень(A^2+B^2)= Квадратный_Корень(22.09+ 38,44)= 7,7801.


рис 31

Полезные слова из предыдущих десяти примеров:

: Hypotenuse ( A B -> C P ) \ C=Квадратный_Корень(A^2+B^2) P=A+B+C

FDUP F* FSWAP FDUP F* F+ FSQRT ; \ A B -> SQRT(A^2+B^2)

: RightTriangleP ( A B C -> P ) \ P=A+B+C

F+ F+ ;

: TriangleP ( A B C -> P ) \ P=A+B+C

F+ F+ ;

Если даны только 2 катета, то можем вычислить периметр так:

3E 4E FOVER FOVER Hypotenuse TriangleP F.

12.000000 Ok

: R1 ( X1 X2 -> R1=|X1-X2| ) \ R1 – расстояние между двумя точками на прямой

F- FABS \ X1 X2 -> |X1-X2|

;

: R2 ( X1 Y1 X2 Y2-> R ) \ R= SQRT{[X2-X1]^2+[Y2-Y1]^2}

\ R2 – расстояние между двумя точками на плоскости

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

;


BEGIN 21-30

Перед решением очередного примера рассмотрим, как объявляются и используются переменные в SP-Forth. Так как операции с большим количеством данных на стеке становится крайне затруднительным, нам они пригодятся. Для этого воспользуемся зарезервированными словами VARIABLE и FVARIABLE. Первое для целых чисел, второе для вещественных. Если кто-то не знает, что такое переменная, то это просто участок памяти, в которое записывается значение (число для целых переменных или вещественных, текст для строковых или их комбинация для структур), считывается и изменяется. На самом деле любые данные, неважно что: простые переменные, структуры или даже файлы, все они кодируется исключительно числами, причем в двоичном формате (нулями и единицами).

Создадим две переменные

FVARIABLE FVAR \ FVAR переменная вещественного типа

VARIABLE VAR \ VAR переменная целого типа

Теперь инициализируем эти переменные, то есть присвоим начальное значение.

1234E-2 FVAR F!

Ok

4552249 VAR !

Ok

Код «1234E-2» нам уже знаком, он просто переносит число «1234E-2» на вершину вещественного стека, FVAR оставляет адрес вещественной переменной с этим именем, и в итоге «F!» – записывает значение по этому адресу. Целочисленное присвоение выглядит по проще, но суть та же. Сначала также число идет в стек. Слово VAR, аналогично своему собрату, оставляет адрес целочисленной переменной на стеке. А записывает «!» – восклицательный знак. Считывает значения переменных соответственно слова – «F@» и «@». Теперь считаем и выведем на экран значения созданных и инициализированных выше переменных.

VAR @ .

4552249 Ok

Знакомый оператор «.» – точка, печатает на экран целочисленное число, а «F.» – вещественное. Вы можете заметить логику Форта по названию операторов, добавив большую букву «F», многие операции становятся применимы к вещественным операндам. Покажем вышесказанное на примере вывода значения вещественной переменной.