Читать книгу Решение задач по программированию на языке Форт (Forth). Версия 3 (Arsen Gonian) онлайн бесплатно на Bookz (4-ая страница книги)
bannerbanner
Решение задач по программированию на языке Форт (Forth). Версия 3
Решение задач по программированию на языке Форт (Forth). Версия 3
Оценить:

3

Полная версия:

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

И снова обратный порядок, результат идентичен первому варианту с целыми аргументами.

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


рис 55

С вещественными данными слово будет иметь вид:

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.


рис 56

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

По предыдущему опыту мы вводим новую переменную, чтобы уменьшить количество элементов на вещественном стеке. Ответ совпадает с первым вариантом, только вещественного формата, что подтверждает корректность работы написанного слова.


рис 57

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


рис 58

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

Пример 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», который лучше, но для начала может быть менее наглядным.

: B38 ( A B -> X )                   \ X=-B/A

FNEGATE FSWAP F/ ;             \ A B -> -B/A


рис 59

Пример 39. Решение квадратного уравнения. Обратите внимание, что в названии вещественной переменной A опущен префиксы «F», так как в этом слове используется одна переменная одного типа применено такое упрощение. Если вас это пугает, то вы легко можете добавить его. Если все слова книги вы добавляете в один файл, то эта проблема будет актуальной, так же вы можете в названиях слов добавлять суффикс I (Integer), для функций с целочисленными аргументами и F, для вещественных, иначе SP-Forth, будет выводить сообщения «B39 isn't unique ()», что не является ошибкой, но предупреждением, о том, что при вызове слова будет вызвано определенное последней слово. Могут возникнуть скрытые ошибки логики работы. Так если вы определили целочисленное слово, затем вещественное и после вызываете попеременно слова с разными аргументами, то как было сказано выше – будет вызвана исключительно последняя реализация, что неизбежно приведет к ошибке, связанное с тем что слова будут работать с аргументами в разных стеках, в итоге, будет либо нехватка аргументов, либо порча других данных не предназначенных для вашего слова. Изменив названия при помощи суффиксов, вы избавитесь от этих проблем.

FVARIABLE A

: B39 ( A B C -> X1 X2)                   \ X1,X2=(-B+-SQRT(D))/2*A

FROT FDUP A F!       F*             \ A B C -> B C*A

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

FSWAP 4E F* F- FSQRT             \ B C*A B^2 -> B SQRT{B^2-4*C*A=D}

FSWAP -1E F* FSWAP             \ B D^0.5 -> -B D^0.5

FOVER FOVER F+ A F@             \ -B D^0.5 -> -B D^0.5 –B+D^0.5 A

2E F* F/                   \ -B D^0.5 –B+D^0.5 A -> -B D^0.5 [–B+D^0.5]/[A*2]=X1

FROT FROT F- A F@             \ -B D^0.5 X1 -> X1 –B-D^0.5 A

2E F* F/                   \ X1 –B-D^0.5 A -> X1 [–B-D^0.5]/[A*2]=X2

FOVER FOVER F<             \ X1 X2 –> X1 X2 X1

IF FSWAP THEN

;

1E 4E 1E B39 F. F.

–3.7320508 -0.2679491 Ok

X^2+4*X+1=0, D=4^2-4*1*1=16-4=12. X1,X2=(-4+-12^0.5)/(2*1)=-2+-SQRT(3)

X1=-2- 1,732= -3,732, X2=-2+1,732=-0,268.

А вот случай, когда D=0

1E 2E 1E B39 F. F.

–1.0000000 -1.0000000 Ok

Небольшая оптимизация кода (на две строчки короче предыдущего слова):

FVARIABLE A

: B39 ( A B C -> X1 X2)                   \ X1,X2=(-B+-SQRT(D))/2*A

FROT FDUP 2E F* A F!             \ A B C -> B C A

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

FSWAP 4E F* F- FSQRT             \ B C*A B^2 -> B SQRT{B^2-4*C*A=D}

FSWAP FNEGATE FSWAP       \ B D^0.5 -> -B D^0.5

FOVER FOVER F+ A F@ F/       \ -B D^0.5 -> -B D^0.5 [–B+D^0.5]/(2*A)=X1

FROT FROT F- A F@ F/             \ -B D^0.5 X1 -> X1 [–B-D^0.5]/(2*A)=X2

FOVER FOVER F<             \ X1 X2 –> X1 X2 X1

IF FSWAP THEN                   \ X2 X1 || X1 X2

;

Результат такой же, но «2*A» два раза не вычисляется, а сразу сохраняется в переменной «A», «-1E F*» заменен на «FNEGATE» – изменение знака «B» на противоположенный.

Если манипуляции со стеком вам не понятны, то мы можем переписать последнее слово с использованием трех переменных A, B, C, по классической схеме.

FVARIABLE A FVARIABLE B FVARIABLE C

: B39 ( A B C -> X1 X2)                         \ X1,X2=(-B+-SQRT(D))/2*A, X1,X2

C F! B F! A F!                         \ A B C ->

B F@ FDUP -1E F* FSWAP FDUP F*       \ -> -B B^2

A F@ C F@ F* -4E F* F+ FSQRT             \ -B B^2 -> -B {B^2+A*C*(-4)}^0.5=D^0.5

FOVER FOVER F+                   \ -B D^0.5 -> -B D^0.5 -B+D^0.5

A F@ 2E F* F/                         \ -B D^0.5 -B+D^0.5-> -B D^0.5 [-B+D^0.5]/[A*2]=X1

FROT FROT F-                         \ -B D^0.5 X1 -> X1 -B-D^0.5

A F@ 2E F* F/                         \ X1 [-B-D^0.5]/[A*2]=X2

FOVER FOVER F<                   \ X1 X2 X1

IF FSWAP THEN

;

1E 4E 1E B39 F. F.

–3.7320508 -0.2679491 Ok

Ответ как в предыдущих вариантах. Какой проще и понятнее решайте сами.


рис 60 результат работы оптимизированного варианта слова с одной переменной

Пример 40. Задача решения системы из двух линейных уравнений с двумя неизвестными. Пропустим вариант с целочисленными аргументами и перейдем к общему случаю.

FVARIABLE A1 FVARIABLE B1 FVARIABLE C1

FVARIABLE A2 FVARIABLE B2 FVARIABLE C2

: B40 ( A1 B1 C1 A2 B2 C2 -> X Y ) \ X=(C1*B2-C2*B1)/D, Y=(A1*C2-A2*C1)/D, D=A1*B2-A2*B1

C2 F! B2 F! A2 F! C1 F! B1 F! A1 F!             \ A1 B1 C1 A2 B2 C2 ->

A1 F@ B2 F@ F* A2 F@ B1 F@ F* F-             \ -> A1*B2-A2*B1=D

FDUP .” D=“ FDUP F. CR                         \ D -> D D

C1 F@ B2 F@ F* C2 F@ B1 F@ F* F- FSWAP F/       \ D D -> D (C1*B2-C2*B1)/D=X

A1 F@ C2 F@ F* A2 F@ C1 F@ F* F- FROT F/       \ D X -> X (A1*C2-A2*C1)/D=Y

;

Здесь мы создали 6 новых вещественных переменных, чтобы не путаться в коэффициентах.

Первая строка – стандартное описание логики работы слова.

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

Вычисление D.

Дублируем D, так как он нам понадобится два раза, также мы его копируем и печатаем для проверки промежуточных вычислений. После отладки код «.” D=“ FDUP F. CR» можно удалять.

Вычисление X

Вычисление Y

Проверим корректность работы слова на следующих данных

3x+5y=7      (A1=3      B1=5      C1=7)

6x+y=4            (A2=6      B2=1      C2=4)

3E 5E 7E 6E 1E 4E B40 F. F.

D= -27.000000

1.1111111 0.4814814 Ok


рис 61

D=3*1-6*5=3-30=-27, совпадает с результатом выданном словом. X=(7*1-4*5)/(-27)=13/27=(0,481). Y=(3*4-6*7)/(-27)=(12-42)/(-27)=30/27=1,(1). Видим, что слово работает корректно.


Integer 1-30

Теперь мы решаем новую группу заданий с исключительно целочисленными параметрами. Все задания мы будем нумеровать с префиксом I, сокращение от Integer, означающее целое число.

Пример 1. Перевести см в м без округления. Здесь вы увидите всю красоту Форта.

Rm=Rcm/100 – целочисленно

: I1 ( Rcm -> Rm ) 100 / ;

503 I1

Ok ( 5 )

Что означает в 503 см содержится 5 полных метров.


рис 62

Пример 2. Отличается от предыдущего заменой 100 на 1000.

Mt= Mkg/1000

: I2 ( Mkg -> Mt ) 1000 / ;

12683 I2

Ok ( 12 )


рис 63

В 12683 кг 12 полных тонн.

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

DkB= DB/1024

: I3 ( DB -> DkB ) 1024 / ;

2050 I3

Ok ( 2 )

2050 B – это 2 полных kB.


рис 64

Пример 4. Так же простейшая задачка на целочисленное деление.

Для определенности A>B, результат равен A/B.

: I4 ( A B -> A/B ) / ;

15 4 I4

Ok ( 3 )


рис 65

В отрезке длиной 15 размещается 3 целых отрезка длиной 4.

Пример 5. Отличается от предыдущего примера заменой целочисленного деления на взятие остатка от деления.

: I5 ( A B -> остаток{A/B} ) MOD ;

15 4 I5

Ok ( 3 )

15/4 – остаток равен 3 – все верно, результат теста корректный.


рис 66

Примеры 1-5 настолько просты, что даже нет необходимости создавать соответствующие слова. Можно просто ввести число-операнд затем тело слова. Результат получите в скобках на стеке. Чтобы распечатать его и не засорять стек нажмите «.» и «Enter». Перепишем эти примеры для наглядности.

«503 100 / .»

«12683 1000 / .»

«2050 1024 / .»

«15 4 / .»

«15 4 MOD .»


рис 67

Но если вы будете часто пользоваться написанным кодом, крайне желательно создавать отдельные слова-функции, также дайте им легко запоминающиеся осмысленные названия.

Пример 6. Вывести число десятков и единиц двузначного числа. Для этого используем операцию /MOD, которая одновременно вычисляет и целую часть, и остаток от деления.

: I6 ( AB -> A B ) 10 /MOD SWAP ;

45 I6

Ok ( 4 5 )

Чтобы вывести в таком же порядке как на стеке слегка изменим код (помним, что сначала напечатается вершина стека, поэтому перед выводом используем команду SWAP)

45 I6 SWAP . .

4 5 Ok

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

: I6. I6 SWAP . . ;

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

45 I6.

4 5 Ok


рис 68

Результат тот же, но решение выглядит более профессионально и красиво.

Разумеется, эти два слова можно объединить в одно по схеме:

: I6. 10 /MOD SWAP SWAP . . ;

: I6. 10 /MOD . . ;

Два слова SWAP уже будут не нужны, но так для сложных задач не рекомендуется делать, кроме того, как говорилось раннее интерфейс вывода и логику работы алгоритма крайне желательно отделять, так изменение в коде одного не повлияет на другое.

Пример 7. Вычислить сумму и произведение цифр двузначного числа. Дальнейшее развитие предыдущего примера.

: I7 ( AB -> A+B A*B )

10 /MOD       \ AB -> A B

2DUP +             \ A B -> A B A+B

ROT ROT *       \ A B A+B -> A+B A*B

;

45 I7

Ok ( 9 20 )

Сумма цифр числа 45 равна 4+5=9, а произведение 4*5=20, тест корректен.

Конец ознакомительного фрагмента.

Текст предоставлен ООО «Литрес».

Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.

Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.

Вы ознакомились с фрагментом книги.

Для бесплатного чтения открыта только часть текста.

Приобретайте полный текст книги у нашего партнера:


Полная версия книги

Всего 10 форматов

bannerbanner