Метка представляет собой символическое имя, вместо которого компилятор подставляет адрес. В программе на ассемблере можно присвоить имя любому адресу в коде или данных. Обычно метки используются для организации переходов, циклов или каких-то манипуляций с данными. По сути имена переменных, объявленных с помощью директив объявления данных, тоже являются метками.
Но с ними компилятор дополнительно связывает размер переменной. Метка объявляется очень просто: достаточно в начале строки написать имя и поставить двоеточие. Например:
m1: mov ax,4C00h int 21h
Теперь вместо имени m1 компилятор везде будет подставлять адрес комады mov ax,4C00h. Можно объявлять метку на пустой строке перед командой:
exit_app: mov ax,4C00h int 21h
Имя метки может состоять из латинских букв, цифр и символов подчёркивания, но должно начинаться с буквы. Имя метки должно быть уникальным. В качестве имени метки нельзя использовать директивы и ключевые слова компилятора, названия команд и регистров (в этом случае FASM покажет сообщение об ошибке). FASM различает регистр символов в именах меток.
Урок 4. Формулы Excel для начинающих
Можно также объявлять несколько меток на один адрес. Например:
no_error: exit_app: m1: mov ax,4C00h
Подробнее о синтаксисе объявления меток рассказывается в части 25.
Команда LOOP
Для организации цикла предназначена команда LOOP. У этой команды один операнд — имя метки, на которую осуществляется переход. В качестве счётчика цикла используется регистр CX. Команда LOOP выполняет декремент CX, а затем проверяет его значение.
Если содержимое CX не равно нулю, то осуществляется переход на метку, иначе управление переходит к следующей после LOOP команде. Содержимое CX интерпретируется командой как число без знака. В CX нужно помещать число, равное требуемому количеству повторений цикла. Понятно, что максимально может быть 65535 повторений. Ещё одно ограничение связано с дальность перехода.
Метка должна находиться в диапазоне -127…+128 байт от команды LOOP (если это не так, FASM сообщит об ошибке).
Пример цикла
В качестве примера я приведу простую программу, которая будет печатать все буквы английского алфавита. ASCII-коды этих символов расположены последовательно, поэтому можно выводить их в цикле. Для вывода символа на экран используется функция DOS 02h (выводимый байт должен находиться в регистре DL).
use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov ah,02h ;Для вызова функции DOS 02h — вывод символа mov dl,’A’ ;Первый выводимый символ mov cx,26 ;Счётчик повторений цикла metka: int 21h ;Обращение к функции DOS inc dl ;Следующий символ loop metka ;Команда цикла mov ah,09h ;Функция DOS 09h — вывод строки mov dx,press ;В DX адрес строки int 21h ;Обращение к функции DOS mov ah,08h ;Функция DOS 08h — ввод символа без эха int 21h ;Обращение к функции DOS mov ax,4C00h ; int 21h ;/ Завершение программы ;——————————————————- press: db 13,10,’Press any key. $’
Команды «int 21h» и «inc dl» (строки 8 и 9) будут выполняться в цикле 26 раз. Для того, чтобы программа не закрылась сразу, используется функция DOS 08h — ввод символа с клавиатуры без эха, то есть вводимый символ не отображается. Перед этим выводится предложение нажать любую кнопку (но Reset лучше не нажимать). Для примера адрес строки объявлен с помощью метки. Символы с кодами 13 и 10 обозначают переход на следующую строку (символ 13(0Dh) называется CR — Carriage Return — возврат каретки, а символ 10(0Ah) LF — Line Feed — перевод строки . Эти символы унаследованы со времён древних телетайпов, когда текст печатался, как на печатной машинке). Так выглядит результат работы программы:
Вложенные циклы
Иногда требуется организовать вложенный цикл, то есть цикл внутри другого цикла. В этом случае необходимо сохранить значение CX перед началом вложенного цикла и восстановить после его завершения (перед командой LOOP внешнего цикла). Сохранить значение можно в другой регистр, во временную переменную или в стек. Следующая программа выводит все доступные ASCII-символы в виде таблицы 16×16. Значение счётчика внешнего цикла сохраняется в регистре BX.
use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov ah,02h ;Для вызова функции DOS 02h — вывод символа sub dl,dl ;Первый выводимый символ mov cx,16 ;Счётчик внешнего цикла (по строкам) lp1: mov bx,cx ;Сохраняем счётчик в BX mov cx,16 ;Счётчик внутреннего цикла (по столбцам) lp2: int 21h ;Обращение к функции DOS inc dl ;Следующий символ loop lp2 ;Команда внутреннего цикла mov dh,dl ;Сохраняем значение DL в DH mov dl,13 ; int 21h ; mov dl,10 ; / Переход на следующую строку int 21h ;/ mov dl,dh ;Восстанавливаем значение DL mov cx,bx ;Восстанавливаем значение счётчика loop lp1 ;Команда внешнего цикла mov ah,09h ;Функция DOS 09h — вывод строки mov dx,press ;В DX адрес строки int 21h ;Обращение к функции DOS mov ah,08h ;Функция DOS 08h — ввод символа без эха int 21h ;Обращение к функции DOS mov ax,4C00h ; int 21h ;/ Завершение программы ;——————————————————- press db 13,10,’Press any key. $’
Как видите, всё довольно просто. Результат работы программы выглядит вот так:
Источник: pro-prof.com
Сложные математические формулы в программировании
Недавно меня выгнали с работы, поэтому сейчас пытаюсь зарабатывать фрилансом. И вот подвернулась задачка — надо было перевести формулы с языка математики на язык программирования. В случае с простыми формулами это делается достаточно легко. Ведь операторы, такие как +, -, * и т.п. одинаково выглядят как в математике, так и в языках программирования.
Однако, если формулы достаточно сложные, то здесь уже становится не так весело. И времени на эту работу уходит достаточно много. И ошибок можно допустить немало, которые потом трудно выискивать.
Так что сегодня поделюсь своими хитростями работы с математическими формулами в программировании. Надеюсь, кому-нибудь окажется полезным.
Итак, вот пример такой формулы:
Выглядит довольно устрашающе. Но если взять себя в руки и отбросить панику, то можно её переписать на каком-нибудь языке программирования. Однако что делать, если таких формул у вас будет, например, 10. Похожих, но с небольшими отличиями. Неужели создавать 10 почти одинаковых функций?
Можно и так. Но лучше выделить в формулах повторяющиеся выражения и для каждого выражения создать отдельную функцию. А потом уже просто вызывать эти функции с необходимыми параметрами.
В итоге наша формула будет выглядеть примерно так:
А вот так это может быть выполнено в исходном коде программы:
type Point3 = record x1, y1, z1 : Extended; x2, y2, z2 : Extended; x3, y3, z3 : Extended; end; // Вспомогательные функции // (x1 — x2)^2 + (y1 — y2)^2 + (z1 — z2)^2 function a(p : Point3) : Extended; begin Result := Sqr(p.x1 — p.x2) + Sqr(p.y1 — p.y2) + Sqr(p.z1 — p.z2); end; // (x3 — x2)^2 + (y3 — y2)^2 + (z3 — z2)^2 function b(p : Point3) : Extended; begin Result := Sqr(p.x3 — p.x2) + Sqr(p.y3 — p.y2) + Sqr(p.z3 — p.z2); end; // (x1 — x3)^2 + (y1 — y3)^2 + (z1 — z3)^2 function c(p : Point3) : Extended; begin Result := Sqr(p.x1 — p.x3) + Sqr(p.y1 — p.y3) + Sqr(p.z1 — p.z3); end; // F function F(p : Point3) : Extended; var chis, znam : Extended; begin chis := (a(p) + b(p) — c(p)); znam := 2 * Sqrt(a(p)) * Sqrt(b(p)); Result := chis / znam; end;
Ну и для закрепления рассмотрим ещё один пример, посложнее:
Здесь всё выглядит ещё страшнее. Но если присмотреться, то мы здесь увидим уже известные нам выражения, которые мы выделили в первом примере и назвали а, b и c. И эти выражения повторяются в функциях Z01 и Z02, Отличаются эти функции только двумя выражениями (на рисунке ниже я обозначил их как n1 и n2). Поэтому в нашей программе мы можем использовать уже готовые функции а, b и c в новых функциях Z01 и Z02, а упрощённая формула будет такой:
Тогда программный код может быть таким:
//Вспомогательная функция для вычисления Z01. Z2 function Za(p : Point3; n1, n2 : Extended) : Extended; var r1, r2, r3 : Extended; begin r1 := 2 * Sqrt(a(p)) * Sqrt(b(p)); r2 := a(p) + b(p) — c(p); r3 := 4 * Exp(1.5 * Ln(a(p))) * sqrt(b(p)); Result := (n1 / r1) — (r2 * n2 / r3); end; // Z01 function Z01(p : Point3) : Extended; var n1, n2 : Extended; begin n1 := -2*p.x2 + 2*p.x3; n2 := 2*p.x1 — 2*p.x2; Result := Za(p, n1, n2); end; // Z02 function Z02(p : Point3) : Extended; var n1, n2 : Extended; begin n1 := -2*p.y2 + 2*p.y3; n2 := 2*p.y1 — 2*p.y2; Result := Za(p, n1, n2); end;
Как видите, я добавил здесь вспомогательную функцию Za, чтобы уменьшить количество кода в функциях Z01 и Z02. Конечно, если у вас только две таких функции, то вспомогательные функции можно и не делать. Но если 10, 20 и больше, то такой подход существенно уменьшит количество исходного кода и размер исходного файла.
Ну и напоследок ещё один полезный совет — как не запутаться в скобках. В указанных выше примерах скобок не так много, поэтому запутаться сложно. Однако бывают и более навороченные формулы, где запутаться в скобках очень легко. Поэтому, если есть файл с формулами, то я преобразую его в формат рисунка (например, в JPG), открываю в графическом редакторе и там выделяю выражения и отмечаю скобки. Примерно так:
То есть открывающую и закрывающую скобку я выделяю одним цветом. Следующую пару скобок — другим цветом и так далее. И таким образом я выделяю в формуле выражения, которые потом можно перенести в исходный код программы.
Ну что же, на этом всё. Надеюсь, кому-нибудь это поможет сократить время на решение подобных задач. Математика в программировании — это не так уж скучно. Особенно если за это платят деньги )))
Источник: info-master.su
Вычисление по формулам. знакомство со средой turbo pascal 7.0
Цель лабораторной работы: освоить работу в интегрированной среде Turbo Pascal; освоить создание программы с линейным алгоритмом; научиться использовать процедуры вывода на экран.
Написать программу, вычисляющую заданное вариантом арифметическое выражение. Вывести на экран исходную формулу в виде традиционной математической записи с дробной чертой (см. пример выполнения). Вывод на экран реализовать в двух версиях: без использования форматирования и с форматированием. Выполнить программу по шагам (F7).
Обратите внимание на то, что значения переменных автоматически не обнуляются. Подготовить письменный отчет по лабораторной работе.
Для вывода на экран используются стандартные библиотечные процедуры write и writeln. С их помощью можно выводить стандартные типы и строки. Работа этих двух процедур отличается только тем, что после выполнения процедуры writeln курсор переводится на новую строку. Описание процедур:
write (v1 [, v2, v3, …, vn]);
writeln (v1 [, v2, v3, …, vn]);
Эти процедуры могут иметь разное количество параметров v, перечисляемых через запятую. Параметром может быть либо строка символов, заключенная в апострофы, либо идентификатор переменной. Для управления размером поля, в которое выводятся данные, используют конструкцию
Целое число k здесь определяет ширину поля, причем выводимые значения прижимаются к правой границе. Если указанной ширины поля недостаточно, то она автоматически увеличивается до нужного значения. Если k не указано, то ширина поля совпадает с количеством выводимых символов.
Пример вызова процедуры (a и b – переменные, объявленные ранее и имеющие значения):
writeln(‘How do you do?’);
writeln(‘How do you do?’:40);
writeln(‘How do you do?’:40, a, b:10);
Для вещественных чисел можно определить количество цифр в дробной части, используя конструкцию вида v:k:l. Параметр l должен быть целым числом. Если он равен 0, то дробная часть и десятичная точка не выводятся. Если для вещественного числа при выводе не указаны параметры k и l, то оно выводится в виде мантиссы и порядка.
Возможно даже отсутствие параметров. В этом случае вызов процедур выглядит так:
Результатом writeln будет перевод строки, а работа процедуры write вообще не приведет к изменениям на экране.
Логические значения выводятся как TRUE и FALSE.
1)Получить вариант задания у преподавателя
2)Выполнить ручной расчет по формуле с точностью до трех разрядов после запятой.
3)Написать и отладить первую версию программы (с выводом на экран без форматирования)
4)Написать и отладить вторую версию программу (с форматированием при выводе на экран, результат должен содержать 4 разряда после запятой, значения переменных a и b – один разряд после запятой)
6)Представить распечатку отчета преподавателю, защитить отчет (ответить на вопросы преподавателя по проделанной работе), показать выполнение программы по шагам и изменения значений переменных в окне просмотра.
Задание: , a =2.4, b = 2,5
Схема программы состоит из следующих частей:
Присваивание переменным начальных значений
Расчет по формуле
Вывод результата на экран
Объявим три вещественные переменные.
Начальные значения зададим с помощью оператора присваивания:
После выполнения расчета значение переменной b изменится, поэтому сохраним его в другой переменной:
Оператор, который выполнит расчет, выглядит следующим образом (обратите внимание на скобки): b:=a/(a+b);
При записи формулы, в которой есть умножение, в программе необходимо ставить знак умножения. То есть формула, математическая запись которой выглядит таким образом: b=a(a+b), в программе должна быть записана так: b:=a*(a+b);. Возведение в степень в данной лабораторной работе реализуйте через умножение (a*a).
При выводе на экран исходной формулы и результата нам понадобятся три вызова процедуры writeln, каждая из которых будет печатать на новой строке. Первая процедура печатает числитель дроби, вторая – середину формулы и числовой результат, а третья – знаменатель дроби:
После этого блока операторов напишем вызов процедуры readln, которая будет ждать нажатия любой клавиши. Это необходимо, чтобы можно было посмотреть результат вывода на экран.