Loe raamatut: «Язык программирования Форт (Forth). Решение задач по программированию. Версия 2.», lehekülg 2

Font:

По-прежнему, мы считаем «Пи» равным «3,14». Для большей точности мы можем использовать слово «FPI», вместо числового значения в коде, который оставляет значение числа «Пи» на вещественном стеке. Проверим работу этого слова. Введем следующий код:

FPI F.

3.1415927 Ok

Самостоятельно перепишите код, с учетом этих изменений.

Пример 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

;

Посчитаем 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».

: 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* 314e-2 F*       \ R -> R Pi*R^2

;

2537E-2 B14 F. F.

51.193031 4.0377609 Ok

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

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

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

4E F*                   \ S -> 4*S

FPI F/                   \ 4*S -> 4*S/Pi

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

FDUP FPI F*             \ D -> D D*Pi=L

;

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

12345E-3 B15 F. F.

12.455194 3.9646112 Ok

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

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

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

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

;

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

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

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

;

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.

Пример 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

Пример 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.

Пример 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.

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», многие операции становятся применимы к вещественным операндам. Покажем вышесказанное на примере вывода значения вещественной переменной.

FVAR F@ F.

12.340000 Ok

VAR и FVAR – это просто названия, они могут быть любыми – это просто удобное обозначение в стиле Форта. Теперь можем приступить к очередной задачке.

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

FVARIABLE FX1

FVARIABLE FY1

FVARIABLE FX2

FVARIABLE FY2

FVARIABLE FX3

FVARIABLE FY3

FVARIABLE FA

FVARIABLE FB

FVARIABLE FC

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

FVARIABLE FX1 FVARIABLE FY1 FVARIABLE FX2 FVARIABLE FY2 FVARIABLE FX3 FVARIABLE FY3

FVARIABLE FA FVARIABLE FB FVARIABLE FC

: B21 ( FX1 FY1 FX2 FY2 FX3 FY3 -> P S )      \ P=(A+B+C)/2 S=SQRT{P*(P-A) *(P-B) *(P-B)}

FY3 F! FX3 F! FY2 F! FX2 F! FY1 F! FX1 F!                  \ FX1 FY1 FX2 FY2 FX3 FY3 ->

FX1 F@ FY1 F@ FX2 F@ FY2 F@ B20 FDUP FA F!      \ A

FX2 F@ FY2 F@ FX3 F@ FY3 F@ B20 FDUP FB F!      \ A B

FX1 F@ FY1 F@ FX3 F@ FY3 F@ B20 FDUP FC F!      \ A B C

F+ F+ FDUP                                    \ A+B+C=P P

2E F/                                          \ P (A+B+C)/2=p

FDUP FA F@ F-                                    \ P p p-A

FOVER FDUP FB F@ F-                              \ P p p-A p p-B

FSWAP FC F@ F-                              \ P p p-A p-B p-C

F* F* F* FSQRT                                    \ P SQRT{p*(p-A)*(p-B)*(p-C)}=S

;

Строка №1 название слова с комментариями.

Вторая – сохранение координат в соответствующих переменных.

С третьей по пятую – вычисление сторон треугольника с сохранением в переменных A, B, C. Здесь мы не высчитаем расстояния между точками (стороны треугольника), а пользуемся предыдущей задачей, в которой эта проблема решена, просто вызвав ее с параметрами задачи №21.

Шестая строка вычисление периметра и его дублирование

Седьмая вычисление полупериметра.

С восьмой по десятую – вычисление сомножителей в формуле площади.

Одиннадцатая – вычисление площади.

Проверим работу слова на координатах: (1,1; 1,1) (6,1; 1,1) (6,1; 4,1). Это прямоугольный треугольник с катетами 3 и 5.

11E-1 11E-1 61E-1 11E-1 61E-1 41E-1 B21 F. F.

7.5000000 13.830952 Ok

S=3*5/2=15/2=7.5. Гипотенуза равна sqrt(3^2+5^2)= sqrt(9+25)= sqrt(34)= 5,83095. P= 5,83095+3+5= 13,83095.

Что является истиной, то есть задачка запрограммирована корректно.

Если у вас будут проблемы и ошибки введите код в нижеприведенной последовательности.

S" lib\include\float2.f" INCLUDED

: B20 ( X1 Y1 X2 Y2-> R )

FROT F- FDUP F*

FSWAP FROT F- FDUP F*

F+ FSQRT ;

FVARIABLE FX1 FVARIABLE FY1 FVARIABLE FX2 FVARIABLE FY2 FVARIABLE FX3 FVARIABLE FY3

FVARIABLE FA FVARIABLE FB FVARIABLE FC

: B21 ( X1 Y1 X2 Y2 X3 Y3 -> P S ) FY3 F! FX3 F! FY2 F! FX2 F! FY1 F! FX1 F! FX1 F@ FY1 F@ FX2 F@ FY2 F@ B20 FDUP FA F! FX2 F@ FY2 F@ FX3 F@ FY3 F@ B20 FDUP FB F! FX1 F@ FY1 F@ FX3 F@ FY3 F@ B20 FDUP FC F! F+ F+ FDUP S" 2E" >FLOAT DROP F/ FDUP FA F@ F- FOVER FDUP FB F@ F- FSWAP FC F@ F- F* F* F* FSQRT ;

11E-1 11E-1 61E-1 11E-1 61E-1 41E-1 B21 F. F.

Здесь нет комментариев в коде, чтобы избежать ошибок при копировании. Первая строка подключение библиотеки для работы с вещественными числами (тип float2). Далее идет код предыдущего примера, который мы используем (в других языках это называется функция). Затем объявляются переменные где мы сохраняем координаты и вычисляемые длины сторон. И, наконец сжатый код слова, производящий вычисления периметра и площади треугольника, и его вызов с заранее подготовленными параметрами.

Пример 22. Довольно классическая задача по обмену содержимым между двумя переменными. В Форте создание переменных в данном случае даже не обязательна.

: B22 ( A B -> B A) SWAP ;

5 4 B22

Ok ( 4 5 )

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

: B22 ( A B -> B A) FSWAP ;

Теперь напишем с переменными:

VARIABLE A

VARIABLE B

: B22 ( -> )      \ обмен содержимым двух переменных A и B

A @ B @ A ! B ! ;

Как проверить работу?

15 A ! 50 B !      \ Сначала инициализируем переменные. A=15, B=50

Ok

B22            \ Вызов функции обмена переменных

Ok

A @ . B @ .      \ Печатаем содержимое переменных после обмена

50 15 Ok

Обмен вещественных переменных.

FVARIABLE FA

FVARIABLE FB

: B22 ( -> )      \ обмен содержимым для двух переменных A и B

FA F@ FB F@ FA F! FB F! ;

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

35E-1 FA F!      \ A=3.5

Ok

77E-1 FB F!       \ B=7.7

Ok

B22

Ok

FA F@ F. FB F@ F.

7.7000000 3.5000000 Ok      \ A=7.7 B=3.5

У нас получилось четыре слова с одинаковыми именами, и каждое заменяет предыдущее, о чем нас предупреждает Форт система – SP-Forth сообщением «B22 isn't unique ()». Если вы собираетесь использовать несколько вариантов этих слов, то надо их называть разными именами. Например, как уже говорилось ранее, добавив «F» в начало слов, которые предназначены для работы с вещественными аргументами. Разумеется, в этом примере, первые два варианта (без использования переменных), в которых тело состоит всего лишь из одного оператора, в отдельные Форт-слова оформлять не обязательно. Просто помните о возможности таких манипуляций на стеке – это одна из сильных сторон Форта.

Пример 23. Обменять значения трех переменных A, B, C по следующей схеме: A -> B -> C -> A.

VARIABLE A VARIABLE B VARIABLE C

Если у вас все примеры в одном файле, то каждый раз объявлять переменные не надо. Добавьте только новую, в данном случае – это «VARIABLE C». Иначе будут сообщения от Форт системы

A isn't unique ()

B isn't unique ()

Это не критично, SP-Forth будет работать дальше, но, во-первых, будут созданы новые переменные с такими же именами, что просто будет бесполезно увеличивать расходы памяти, во-вторых, если вам нужно было предыдущее значение, то они уже не будут доступны по имени.

: B23 ( -> )             \ стековая нотация по прежнему пуста

A @ B @ C @       \ -> A B C

A ! C ! B !       \ A=C C=B B=A

;

1 A ! 2 B ! 3 C ! B23 A @ . B @ . C @ .

3 1 2 Ok

A=3, B=1, C=2.

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

FVARIABLE FA FVARIABLE FB FVARIABLE FC

: B23 ( -> )                   \ стековая нотация по прежнему пуста

FA F@ FB F@ FC F@       \ -> A B C

FA F! FC F! FB F!       \ C=A B=C A=B

;

1E FA F! 2E FB F! 3E FC F! B23 FA F@ F. FB F@ F. FC F@ F.

3.0000000 1.0000000 2.0000000 Ok      \ FA=3 FB=1 FC=2

Пример 24. Аналогичен предыдущему с перемещением содержимого по схеме: A -> C-> B -> A.

Переменные используем с предыдущего примера.

: B24 ( -> )      \ стековая нотация пуста

A @ B @ C @      \ -> A B C

B ! A ! C !      \ B=C A=B C=A

;

1 A ! 2 B ! 3 C !            \ инициализация A=1 B=2 C=3

Ok

B24                  \ вызов нашей функции

Ok

A @ . B @ . C @ .      \ A=2 B=3 C=1

2 3 1 Ok

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

: B24 ( -> ) \ стековая нотация пуста

FA F@ FB F@ FC F@       \ -> A B C

FB F! FA F! FC F!       \ B=C A=B C=A

;

Проверим на аналогичных данных.

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 ()», что не является ошибкой, но предупреждением, о том, что при вызове слова будет вызвано определенное последней слово. Могут возникнуть скрытые ошибки логики работы. Так если вы определили целочисленное слово, затем вещественное и после выполняете попеременно слова для разных аргументов, то как было сказано будет вызвана исключительно последняя реализация, что неизбежно приведет к ошибке, связанное с тем что слова будут работать с аргументами в разных стеках, в итоге, будет либо нехватка аргументов, либо порча других данных не предназначенных для этого. Изменив названия при помощи префиксов, вы избавитесь от этих проблем.

Tasuta katkend on lõppenud.

Vanusepiirang:
12+
Ilmumiskuupäev Litres'is:
11 detsember 2023
Kirjutamise kuupäev:
2023
Objętość:
190 lk 1 illustratsioon
Õiguste omanik:
Автор
Allalaadimise formaat:
Tekst
Средний рейтинг 4,8 на основе 36 оценок
Tekst PDF
Средний рейтинг 4,8 на основе 5 оценок
Tekst PDF
Средний рейтинг 3 на основе 6 оценок
Tekst PDF
Средний рейтинг 5 на основе 2 оценок
Tekst PDF
Средний рейтинг 4,5 на основе 2 оценок
Tekst PDF
Средний рейтинг 4,6 на основе 5 оценок
Tekst PDF
Средний рейтинг 4,5 на основе 4 оценок
Audio
Средний рейтинг 5 на основе 5 оценок