DUP * 6 * \ A^3 A -> A^3 A^2*6 – V=A^3 S=6*A^2
;
Поясним код:
Во второй строчке кода 2DUP, в отличие от DUP дублирует сразу 2 верхних элемента, совместное использование (DUP и 2DUP) оставляют четыре числа A.
В третьей, два умножения «* *» приводят к вычислению куба ( A A A A -> A A*A*A=A^3 ).
В четвертой, SWAP меняет куб числа «A» с ним самим местами ( A A^3 -> A^3 A ).
В пятой, «DUP *» (A^3 A -> A^3 A*A ), возводит в квадрат число на вершине стека, а «6 *» умножает его на шесть. В результате получаем площадь боковой поверхности.
Вызовем написанное слово с параметром 15 (сторона куба):
15 B5
Ok ( 3375 1350 )
3375=15*15*15 и 1350=6*15*15, все верно, слово работает корректно.
То же самое с вещественными числами:
: B5 ( A -> V S ) \ V=A^3 S=6*A^2
FDUP FDUP FDUP \ A -> A A A A – 2FDUP SP-Forth не понимает
F* F* \ A A A A -> A A*A*A=A^3
FSWAP \ A A^3 -> A^3 A
FDUP F* \ A^3 A -> A^3 A*A
6E F* \ A^3 A*A -> A^3 6*A^2
;
Проверим написанный код, возьмем куб со стороной 1,5:
15E-1 B5 F. F.
13.500000 3.3750000 Ok \ 6*1.5^2 = 13.5 1.5^3 = 3.375
Помните, что оператор «F.» печатает то, что лежит на вершине стека. Если вам нужен другой порядок можно применить FSWAP, так при необходимости вывести сперва объем, как в стековой нотации, можно набрать следующее:
15E-1 B5 FSWAP F. F.
3.3750000 13.500000 Ok
Пример 6. Здесь необходимо вычислить объем и площадь поверхности прямоугольного параллелепипеда, через его ребра.
: B6 ( A B C -> S V ) \ S=2*(A*B+B*C+A*C) V=A*B*C )
DUP 2OVER \ A B C -> A B C C A B
DUP 2OVER \ A B C C A B -> A B C C A B B C A
ROT * \ A B C C A B B C A -> A B C C A B C A*B
ROT ROT * + \ A B C C A B C A*B -> A B C C A (A*B+B*C)
ROT ROT * + \ A B C C A A*B+B*C -> A B C (A*B+B*C+C*A)
2* \ A B C (A*B+B*C+C*A) -> A B C (A*B+B*C+C*A)*2
SWAP 2SWAP \ A B C (A*B+B*C+C*A)*2 -> (A*B+B*C+C*A)*2 C A B
* * ; \ (A*B+B*C+C*A)*2 (C*A*B)
Где (A*B+B*C+C*A)*2 – это площадь поверхности, а (C*A*B) – объем.
В данном примере появляется 3 параметра, что не слишком усложняет задачу, и по-прежнему мы не будем использовать переменные в явном виде, манипулируя только с данными на стеке.
В коде для вещественных чисел надо, чтобы число элементов не превышало максимума, из-за его ограниченности произойдет ошибка. Проверим сколько вмещает наша система, для этого наберем следующие команды:
FDEPTH \ Это слово возвращает количество элементов в вещественном стеке
Ok ( 0 ) \ 0 элементов
5E-1 FDEPTH \ введем 1-ое число
Ok ( 0 1 ) \ 1 элемент на вещественном стеке
5E-1 FDEPTH \ введем 2-ое число
Ok ( 0 1 2 ) \ 2 элемента
5E-1 FDEPTH \ введем 3-е число
Ok ( 0 1 2 3 ) \ 3
5E-1 FDEPTH \ введем 4-ое число
Ok ( 0 1 2 3 4 ) \ 4
5E-1 FDEPTH \ введем 5-ое число
Ok ( [6].. 1 2 3 4 5 )
5E-1 FDEPTH \ введем 6-ое число
Ok ( [7].. 2 3 4 5 6 )
5E-1 FDEPTH \ введем 7-ое число
Ok ( [8].. 3 4 5 6 7 )
5E-1 FDEPTH \ ошибка !!!
Если после ошибки ввести «F.» получим:
infinity Ok
После ошибки лучше перезапустить SP-Forth. Так же не забывайте о подключении библиотек заново для работы с вещественными числами. Существует слово DEPTH для обычного стека, которое также оставляет количество его элементов, не считая возвращаемый параметр.
Теперь перепишем Пример 6 для вещественных чисел.
: B6 ( A B C -> S V ) \ S=2*(A*B+B*C+A*C) V=A*B*C )
FOVER FOVER F+ \ A B C -> A B C (B+C)
FROT FROT F* \ A B C (B+C) -> A (B+C) B*C
FROT \ A (B+C) B*C -> (B+C) B*C A
FOVER FOVER F* \ (B+C) B*C A -> (B+C) B*C A B*C*A
F. \ 1-ый результат – объем
FROT F* F+ 2.E F* \ (B+C) B*C A -> {B*C+A*(B+C)}*2
F. \ 2-ой результат S=2*(A*B+B*C+A*C)
;
Теперь можно проверить как работает написанное слово:
1E-1 2E-1 3E-1 B6
0.0060000 0.2200000 Ok
Объем прямоугольного параллелепипеда 0,006=0,1*0,2*0,3 и площадь его поверхности 0,22=2*(0,1*0,2+0,2*0,3+0,1*0,3).
Пример 7. Зная радиус окружности, посчитаем его длину и площадь.
: B7 ( R -> L S) \ L=2*Pi*R и S=Pi*R^2
DUP 2* 314 * \ R -> R R*2*314=L
SWAP \ R L -> L R
DUP 314 * * \ L R -> L R*R*314=S
;
Целочисленный вариант принимает целое значение радиуса и выдает результат в 100 раз больше. Надеюсь по комментариям стековой нотации работа слова понятна (она довольно тривиальна).
Код для вещественного аргумента:
: B7 ( R -> L S) \ L=2*Pi*R и S=Pi*R^2
FDUP 2E F* 314E-2 F* \ R -> R 2*Pi*R=L
FSWAP \ R L -> L R
FDUP 314E-2 F* F* \ L R -> L R*R*3.14=S
;
Вычислим длину окружности и площадь круга радиусом 0,1:
1E-1 B7 F. F.
0.0314000 0.6280000 Ok
0.0314000=0,1*0,1*3,14 и 0.6280000= 2*3,14*0,1. Результаты теста корректны.
Пример 8. Простая задачка на вычисление среднего арифметического двух целых чисел:
: B8 ( A B -> [A+B]/2 ) + 2/ ;
1 3 B8
Ok ( 2 )
Мини-код работает правильно (1+3)/2=2. Ниже приведем код для вещественного аргумента:
: B8 ( A B -> [A+B]/2 )
F+ 2E F/ ;
1E-1 2E-1 B8 F.
0.1500000 Ok
0.15 = (0.1+0.2)/2 – ИСТИНА
Пример 9. Среднее геометрическое двух чисел – это квадратный корень из их произведения. Сразу напишем код для вещественного аргумента, так как возможности извлечение корня для целых чисел в системе SP-Forth нет, для этого придётся переводить целое число в вещественное извлечь квадратный корень, затем перевести обратно в целый вид, поэтому здесь такие хлопоты не оправданы, но если где-то вам это понадобится, то знайте такое возможно.
: B9 ( A B -> SQRT[A*B] )
F* FSQRT ;
Очень короткий и понятный код, который тестируем ниже:
3E-1 75E-1 B9 F.
1.5000000 Ok \ 1,5 = Корень_Квадратный_из(0,3*7,5) – ИСТИНА
Этот и предыдущий примеры можно оформить красиво, для дальнейшего использования в математических вычислениях или в других программах, как ваши библиотечные функции.
: MIDDLE_ARITHMETIC ( A B -> [A+B]/2 ) F+ 2E F/ ;
: MIDDLE_GEOMETRIC ( A B -> SQRT[A*B] ) F* FSQRT ;
За грамотные английские названия не ручаюсь.
Пример 10. Вход два числа, не равные нулю. Вычислим сумму, разность, произведение и частное их квадратов, те есть:
: B10 ( A B -> A^2+B^2 A^2-B^2 A^2*B^2 A^2/B^2 )
SWAP DUP * SWAP DUP * \ A B ->A^2 B^2
2DUP + \ A^2 B^2 -> A^2 B^2 (A^2+B^2)
ROT ROT 2DUP – \ A^2 B^2 (A^2+B^2) -> (A^2+B^2) A^2 B^2 (A^2-B^2)
ROT ROT 2DUP * \ (+) A^2 B^2 (-) -> (+) (-) A^2 B^2 (A^2*B^2)
ROT ROT / \ (+) (-) A^2 B^2 (*) -> (+) (-) (*) (A^2/B^2 )
;
Протестируем на числах 4 и 2.
4 2 B10
Ok ( 20 12 64 4 )
Всё корректно, проверяйте самостоятельно. В комментариях я сократил сумму, разность и произведение квадратов до соответствующих операций в скобках. Специально подобраны такие числа, чтобы результат деления был целочисленным, но это не обязательно – код для вещественных аргументов избавит нас от таких неудобств:
: B10 ( A B -> A^2+B^2 A^2-B^2 A^2*B^2 A^2/B^2 )
FSWAP FDUP F* \ A B -> B A^2
FSWAP FDUP F* \ B A^2 -> A^2 B^2
FOVER FOVER F+ \ A^2 B^2 -> A^2 B^2 (A^2+B^2)
FROT FROT FOVER FOVER F- \ A^2 B^2 (A^2+B^2) -> (A^2+B^2) A^2 B^2 (A^2-B^2)
FROT FROT FOVER FOVER F* \ (+) A^2 B^2 (-) -> (+) (-) A^2 B^2 (A^2*B^2)
FROT FROT F/ \ (+) (-) A^2 B^2 (*) -> (+) (-) (*) (A^2/B^2)
;
Тест примера 10:
1E-1 2E-1 B10 F. F. F. F.
0.2500000 0.0004000 -0.0300000 0.0500000 Ok
Не забываем, что оператор F. Печатает число с вершины стека, поэтому сначала напечатается частное, затем произведение, после чего разность и в конце сумма.
0,25 = 0,01/0,04; 0,0004 = 0,01*0,04; -0,03 = 0,01-0,04; 0,05 = 0,01+0,04.
Если вам нужен другой порядок вывода результатов, то самостоятельно решите эту задачу.
BEGIN 11-20
Пример 11. Отличается от 10-ого примера незначительными поправками. Просто заменяем квадрат на модуль: код «DUP *» на «ABS».
: B11 ( A B -> {|A|+|B|} {|A|-|B|} {|A|*|B|} {|A|/|B|} )
SWAP ABS SWAP ABS \ A B ->|A| |B|
2DUP + \ |A| |B|-> |A| |B| (|A|+|B|)
ROT ROT 2DUP – \ |A| |B| (|A|+|B|) -> (|A|+|B|) |A| |B| (|A|-|B|)
ROT ROT 2DUP * \ (+) |A| |B| (-) -> (+) (-) |A| |B| (|A|*|B|)
ROT ROT / \ (+) (-) |A| |B| (*)-> (+) (-) (*) (|A|/|B|)
;
В случае для вещественных аргументов:
: B11 ( A B -> {|A|+|B|} {|A|-|B|} {|A|*|B|} {|A|/|B|} )
FSWAP FABS \ A B -> B |A|
FSWAP FABS \ B |A| -> |A| |B|
FOVER FOVER F+ \ |A| |B|-> |A| |B| (|A|+|B|)
FROT FROT FOVER FOVER F- \ |A| |B| (|A|+|B|) -> (|A|+|B|) |A| |B| (|A|-|B|)
FROT FROT FOVER FOVER F* \ (+) |A| |B| (-) -> (+) (-) |A| |B| (|A|*|B|)
FROT FROT F/ \ (+) (-) |A| |B| (*)-> (+) (-) (*) (|A|/|B|)
;
В комментариях стековой нотации (скобках) соответствующие сумма, разность, произведение и частное взяты в фигурные скобки для визуального выделения элементов на стеке. Обычные скобки в данном случае применять нельзя, так как они обозначают комментарий и являются зарезервированными словами Форта и системы программирования 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 и 4:
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
Можете самостоятельно проверить истинность теста.
Пример 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. Теперь перепишем данный пример для случая с вещественными аргументами.
: 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.».
По-прежнему, мы считаем «Пи» равным «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
О проекте
О подписке