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

Schriftart:

На сайте hi-aga.ru вы можете скопировать текст кода программ без искажений, связанные с форматированием текста (исходник книги в формате doc), также возможны некорректное отображение номеров страниц в оглавлении (по той же причине). По ссылке hi-aga.ru вы также найдете дополнительные материалы, не вошедшие в данную книжку. Сайт будет дополняться чаше нежели книжка. Об обнаруженных ошибках, также можете сообщить по контактам на сайте.

Оглавление

0 Введение                                                            3

1.1 BEGIN 1-10                                                            6

1.2 BEGIN 11-20                                                      15

1.3 BEGIN 21-30                                                      21

1.4 BEGIN 31-40                                                      32

2 Integer 1-30                                                            39

3.1 Boolean 1-20                                                      48

3.2 Boolean 21-40                                                      67

4 If 1-30                                                            88

5 Case 1-20                                                            123

6 FOR 1-40                                                            153

7 While 1-30                                                            189

8 Литература                                                            223

Введение

Эта книга поможет вам освоить язык программирования Форт с нуля. Синтаксис этого ЯП (Языка Программирования) настолько прост, что его практически нет. Есть только одно главное правило – все Слова (именно так называются операторы языка и определяемые пользователем слова-функции) и числа должны быть разделены между собой хотя бы одним символом пробела и/или табуляции и/или переноса строки (то есть «любой символ разделитель»).

Для кого этот сайт?

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

Среда программирования SP-Forth – замечательно подойдет для наших целей. Программирование в этом консольном приложении можно начать сразу после быстрого скачивания и установки с официального сайта последней его версии (SP-Forth свободное ПО с открытым исходным кодом). Работать мы будем в режиме интерпретатора. Это значит, что после запуска системы программирования SP-Forth можно вводить команды или целую программу, после, нажав <Enter>, приложение обработает код и выдаст, предусмотренные кодом результаты. Скачивание и установка SP-Forth не должен вызвать никаких сложностей, а потому этот процесс мы здесь опустим.

Исторически сложилось, что основы программирования начинают изучать с первой программы, которая выводит на экран «Hello, World!», что по-русски означает «Здравствуй, Мир!».

Код для ЯП Форт будет следующий:

.( Hello world!)

или

S" Hello, World!" TYPE

После чего на экран будет выведено вышеупомянутое сообщение. Операторы ЯП (язык программирования) Форт <.(> и <S">: первый берет текст, следующий за ним до закрывающей скобки – ")” (признак конца строки) и печатает его на экран, второй создаёт строку адрес которой с ее длиной отправляется на стек. Затем оператор TYPE используя эти числа, адрес и его размер, как параметры также печатает сообщение. Главное «TYPE» должен идти сразу, во избежание ошибок при исполнении, это особенность работы системы. Обращайте внимание на пробелы – в форте они разделяют слова языка. Зачем нужен второй вариант, если первый проще и короче? Затем что он универсальный, так определяются в Форте строки, и они будут полезны в будущем.

Третий вариант этой же программы будет выглядеть так:

: Hello_World ." Hello, World!" ;

Hello_World

Отличие в том, что мы определяем одноименное слово, которое затем вызывается. Первые два варианта работают в режиме интерпретации, а последний, компиляции (в форт-словаре создается новое слово). Будучи универсальным, его можно вызывать многократно из различных мест программы или даже использовать сей код в своих библиотеках.

Так мы написали первую полноценную программку. Вместо Hello_World, вы его можете назвать Start или как захочется, главное придерживаться простого правила – названия должны быть информативными. Стиль программирования на ЯП Форт ничем не отличается от других языков, будет полезно в дальнейшем почитать об этом дополнительно, для правильного оформления своего кода.

Так мы определили новое слово. Определение слова начинается с двоеточия, затем идет любой символ-разделитель (пробел, табуляция или перевода строки). После идёт имя слова, которое вы сами придумаете, далее код – реализация (последовательность операторов, чисел и других уже определённых слов), разделенных пробелами. Завершается точкой с запятой, также отделенный от кода пробелом.

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

Добавим пару штрихов. Комментарии:

Принято в каждом определении нового слова после названия писать комментарий, обозначающий что слово берет со стека в качестве параметров и что оставляет на нем. Перепишем наше первое Форт-Слово:

: Hello_World ( -> ) ." Hello, World!" ; Hello_World

Так как Hello_World оставляет стек без изменений (не трогает его), то до и после стрелки ничего нет. Комментарий – это содержимое скобок.

Также существует второй способ комментирования кода до конца строки. Это символ – «\».

\ это программа, выводящая сообщение «Hello, World!»

: Hello_World ( -> ) ." Hello, World!" ;

Hello_World

Программировать самому не составляет особой сложности даже для совсем начинающих. Это вам не язык программирования С или С++. Все довольно наглядно и просто. Можно практиковать программирование онлайн или офлайн. Для первого варианта существует скрипт транслятор языка форт. Мы же будем ориентироваться на конкретный диалект – SP-Forth. Он существует для разных систем (Windows, Linux).

Обычно вторая задача при обучении программированию – это написание калькулятора. В Форте калькулятор писать не нужно, так как он поддерживает основные операции изначально, правда несколько в необычном формате, которая называется обратная польская запись или постфиксная форма записи. В математике вы привыкли писать формулы в инфиксной форме типа (1+2)*5/(4-5), где знак бинарной операции пишется между числами, к примеру в Лиспе сначала идёт операция, а затем операнд или операнды, а в форте наоборот, сперва мы отправляем на стек операнды, затем операция забирая их оттуда, выполняет действия над ними, оставляя результат там же. Стек это просто место в памяти, поддерживаемое на аппаратном уровне, следовательно, все операции над ними выполняются очень быстро, где будет хранится наши промежуточные данные.

Так будет выглядеть работа с нашим калькулятором:

Операнд1 Операнд2 Операция. То есть вместо 1+2 в Форте мы должны написать «1 2 +».

1 2 +

Ok ( 3 )                   \ 1+2=3 в скобках – это содержимое стека

1 2 *

Ok ( 3 2 )                   \ 1*2=2 очередной результат на вершине стека

1 2 -

Ok ( 3 2 4294967295(-1) )      \ 1-2=-1, 4294967295 – это без знаковый вариант числа -1

1 2 /

Ok ( 3 2 4294967295(-1) 0 )      \ 1/2=0 – это целочисленное деление, потому результат нуль

1 2 MOD

Ok ( 3 2 4294967295(-1) 0 1 )      \ остаток от деления 1/2

1 2 /MOD

Ok ( [7].. 4294967295(-1) 0 1 1 0 )      \ остаток от деления 1/2 и целая часть 1/2

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

Приведем примеры на SP-Forth.

: ^2 ( A -> A^2 ) DUP * . ;            \ возведение числа в квадрат

: ^3 ( A -> A^3 ) DUP DUP * * . ;            \ возведение числа в куб

: ^4 ( A -> A^4 ) DUP * DUP * . ;            \ возведение числа в четвертую степень

DUP – это слово которое просто дублирует число на вершине стека.

Возведём 5 в квадрат, для этого наберём на клавиатуре:

5 ^2

25 Ok

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

: ^2 ( A -> A^2 ) DUP * . ;\ возведение числа в квадрат

^ -2003 WORD OR FILE NOT FOUND

При «Копи пасте» куда-то делись символы табуляции между «;» и комментарием, вследствие видим сообщение об ошибке, из-за нарушения синтаксиса.

Также, вместо ^2, можно слово назвать **2, в стиле python:

: **2 ( A -> A^2 ) DUP * . ;            \ возведение числа в квадрат

5 **2

25 Ok

В итоге получаем тот же ответ, но стилистика программы изменилась.

Для начала этого достаточно. Далее при решении конкретных задач, в среде программирования SP-Forth, процесс станет более понятным и осознанным.

BEGIN 1-10

Практику программирования начнем с задач из книги М. Э. Абрамян "1000 задач по программированию Часть I Скалярные типы данных, управляющие операторы, процедуры и функции" 2004. Автор пишет, что получить задачник можно по e-mail: mabr@math.rsu.ru или за подробностями обращайтесь к веб ресурсу ptaskbook.com. Текст задач я приводить не буду, дабы исключить плагиат. Думаю, пояснения к коду с описанием слов (функций-программ) должно быть достаточно, в противном случае обращайтесь к первоисточнику за текстом задач.

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

: B1 ( A -> P ) 4 * ; \ P=4*A

B – это сокращение от BEGIN, что обозначает первую группу заданий (мы и далее будем использовать такой вид названий в последующих группах заданий), затем слитно пишется номер примера. Сразу после имени в скобках пишется комментарий стековой нотации. Так принято в Форте. В данном случае Слово-функция B1 берет один параметр A (четырехбайтовое целое число и оставляет другое того же типа). A – сторона квадрата – вход функции, P – его периметр – возвращаемое функцией значение. Тело – очень короткое, просто умножает число на вершине стека на 4 (не забываем, что в Форте обратная польская нотация, сначала идут операнды, затем операция).

Теперь чтобы воспользоваться нашим словом, например, чтобы посчитать периметр квадрата со стороной 3, используем следующий код:

3 B1 .

12 Ok

Точка «.» – это стандартное форт слово, которое печатает число на вершине стека на экран.

Напомним, общий вид определения нового слова в Форте:

: Название-Слова ( стек до выполнение –> после ) Код-Тела-Функции ; \ комментарий

Пример 2. Нам нужно посчитать площадь квадрата:

: B2 ( A -> S ) DUP * ; \ S=A^2

Мы просто дублируем содержащееся на вершине стека число (для чего используем оператор языка Форт – DUP) и умножаем его на себя. Данный пример можно оформить более красиво для использования в ваших будущих программах:

: SQR ( A -> A^2 ) DUP * ;      \ A^2 – вычисление квадрата числа, или

: ^2 ( A -> A^2 ) DUP * ;            \ или

: **2 ( A -> A^2 ) DUP * ;      \ отличие только в названии

Какой нравится, тот и можете использовать. Или все сразу, так тоже можно.

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

: B3 ( A B -> S P ) \ ( S=A*B P=2*(A+B) )

2DUP       \ A B -> A B A B – Слово 2DUP, дублирует сразу два числа на вершине стека

*       \ A B A B -> A B A*B=S – Площадь вычислен – это просто произведение сторон

ROT ROT \ A*B=S A B – оператор ROT вытаскивает 3-ий от вершины параметр на вершину

\ применив его два раза вытаскиваем A B на верх

+ 2* ;       \ складываем A и B, и умножив на 2, оператором 2*, получаем периметр

Слово «2*» делает тоже самое что и два слова «2 *», только короче и проще.

В итоге на стеке мы получаем Площадь и Периметр. Чтобы напечатать результаты на экран из примеров нужно просто ввести точку с клавиатуры «.» и затем нажать «Enter». Сначала напечатается вершина, т. е. периметр, в данном примере, затем повторив действия площадь. Чтобы изменить порядок печати, можно набрать слово SWAP, который меняет местами 2 числа на вершине стека ( A B -> B A), т.е., например чтобы вычислить площадь и периметр прямоугольника со сторонами 1 и 2 введём следующее:

1 2 B3 SWAP . .

2 6 Ok

Площадь равна 1*2=2, а периметр равен 2*(1+2)=6. Слово работает корректно: площадь и периметр вычисляются соответственно стековой нотации, а выводятся по условию задачи.

Пример 4. Нужно вычислить длину круга зная его диаметр:

: B4 ( D -> L ) 314 * ; \ L=Pi*D*100

Ответ буде в 100 раз больше для целочисленных данных, таким образом избавимся от дробной части. Перепишем код, чтобы можно было работать с вещественными числами. Для этого в SP-Forth нужно подключить соответствующие библиотеки. Скопируйте и вставьте следующие две строчки:

S" lib\include\float.f" INCLUDED

S" lib\include\float2.f" INCLUDED

Но можно только вторую строчку.

Теперь чтобы ввести вещественное число, скажем 0,5, нужно набрать на клавиатуре следующее:

5E-1

До E – это мантисса (число), после экспонента (степень). Мантисса и экспонента могут быть как положительными (знак не требуется), так и отрицательными (в данном случае степень -1, что значит 10 в минус первой степени).

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

5E-1 F.

В ответ увидим:

0.5000000 Ok

Слово «F.», аналогично, как и «.» выводит число на вершине стека на экран, только не с целочисленного, а вещественного.

Теперь мы можем переписать пример 4 для вещественных аргументов:

: B4 ( D -> L )            \ L=Pi*D

314E-2 F* ;

Посчитаем длину окружности диаметром 0,5, набрав следующее:

5E-1 B4 F.      \ вызываем слово, которое считает длину и «F.» печатает ответ

1.5700000 Ok

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

Пример 1:

: B1 ( A -> P ) 4E F* ; \ P=4*A

Знак «*» заменяется на «F*», четверка вводится как вещественное число (операция «F*», в отличие от «*» производит операцию над вещественными числами на вещественном стеке). Теперь проверим, посчитаем периметр квадрата со стороной 0,5:

5E-1 B1 F.

2.0000000 Ok

Ответ 2 (0,5*4=2) что является правдой.

Данный пример, так же можно преобразовать, написав в стиле:

: B1 ( A -> P )      \ P=4*A

4E F*

;

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

Пример 2:

: B2 ( A -> S ) FDUP F* ; \ S=A^2

Опять DUP превращается в FDUP, умножение как в первом случае. Проверим работу слова. Посчитаем площадь квадрата со стороной 0,5:

5E-1 B2 F.

0.2500000 Ok            \ 0,5*0,5 = 0,25

Пример 3:

: B3 ( A B -> S P )      \ S=A*B P=2*(A+B)

FOVER FOVER      \ A B -> A B A B

\ Слово FOVER, дублирует слово под вершиной стека на ее вершину т.е. по схеме (A B -> A B A)

\ Повторив его 2 раза получим ( A B -> A B A B )

F* F.            \ A B A B -> A B A*B=S

\ Площадь вычислен – это просто произведение сторон

F+ 2E F* F. ;      \ складываем A и B, и умножив на 2, оператором F*, получаем периметр

Проверим работу слова B3:

2E-1 3E-1 B3

0.0600000 1.0000000 Ok

Как можете увидеть ниже всё работает верно:

S = 0,2*0,3=0,06

P=2*(0,2+0,3)=2*0,5=1

0,2 и 0,3 можно вводить и в следующем виде: 0.2E и 0.3E. Самостоятельно можете убедиться, что слово «F.» выведет на экран тоже самое значение.

Универсальный вариант того же примера, если вы не хотите сразу печатать результаты обработки в слове:

: B3 ( A B -> S P )      \ S=A*B P=2*(A+B)

FOVER FOVER      \ A B -> A B A B

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

\ Площадь вычислен – это просто произведение сторон

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

F+ 2E F* ;      \ складываем A и B, и умножив на 2, оператором F*, получаем периметр

Проверим. Посчитаем площадь и периметр прямоугольника со сторонами 0,2 и 0,3:

2E-1 3E-1 B3

Ok

F. F.

1.0000000 0.0600000 Ok

Сначала выводит периметр затем площадь, чтобы изменить порядок как указано в стековой нотации нужно набрать команду FSWAP перед печатью результатов, то есть:

2E-1 3E-1 B3 FSWAP F. F.

0.0600000 1.0000000 Ok

Результаты по-прежнему верны.

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

Как вы уже могли заметить одно замечательное свойство Форта – его слова-функции не только принимают любое количество аргументов, но также оставляют на стеке желаемое число результатов, не каждый ЯП может этим похвастаться.

Вы можете заметить, что, в примере 3, каждая строка кода сопровождается комментарием, которая поясняет изменения на стеке. Так как все операции и манипуляции, в данном примере, производятся только с вещественным стеком, мы это никак не обозначаем, когда слово будет работать с обоими стеками сразу, вещественный стек будем выделять так: «F: A B A*B=S -> S A B», изменения целочисленного стека дополнительно выделять не будем. Существует еще и стек возвратов. Будьте осторожны, любые неосторожные манипуляции приведут к некорректным результатам, в лучшем случае, в худшем вызовут сообщения об ошибке.

Так же обратите внимание, что комментарии выравниваются так чтобы они выстроились в вертикальную линию, даже те строчки, в которых нет кода, исключительно для удобства чтения.

Пример 5. Здесь вычисляется объем куба и площадь его боковой поверхности. Вначале приведем работу с целочисленным аргументом.

: B5 ( A -> V S )

DUP 2DUP      \ A -> A A A A

* *            \ A A A A -> A A^3

SWAP            \ A A^3 -> A^3 A

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.».

Genres und Tags

Altersbeschränkung:
12+
Veröffentlichungsdatum auf Litres:
11 Dezember 2023
Schreibdatum:
2023
Umfang:
190 S. 1 Illustration
Rechteinhaber:
Автор
Download-Format:
Text PDF
Durchschnittsbewertung 4,8 basierend auf 5 Bewertungen
Text PDF
Durchschnittsbewertung 3 basierend auf 1 Bewertungen
Text PDF
Durchschnittsbewertung 3,7 basierend auf 13 Bewertungen
Text PDF
Durchschnittsbewertung 5 basierend auf 1 Bewertungen
Text PDF
Durchschnittsbewertung 4,1 basierend auf 113 Bewertungen
Audio
Durchschnittsbewertung 5 basierend auf 5 Bewertungen