[an error occurred while processing this directive]
.цв
6. Арифметика вещественных чисел с плавающей точкой
.нф
Для решения широкого круга вычислительных задач Форт-Агат дополнен библиотекой float, которая обеспечивает выполнение основных операций с вещественными числами в диапазоне десятичных чисел от ±0.9999999*10-31 до ±0.9999999*1031. Перечень слов Форта, реализующих эти операции, представлен в табл.6.1 и 6.2.
.цв
Таблица 6.1. Операции с плавающей точкой над числами во float-формате
.нф
.кс-5
floin (--- d) Ожидает ввода числа в формате с плавающей точкой, например:
.цв
-1234.567е-23
.нф
.кс-5
вводит число в текстовую переменную buf3, преобразует ее в двойное число в специальном формате (float-формате), которое кладет на стек
f. (d ---) Выводит из стека на экран двойное число в float-формате, преобразуя его в число с плавающей десятичной точкой, порядком и знаком, например вида:
-0.1234567е-19
f+ (d1 d2 --- d3) Суммирует float-числа d1 и d2 и кладет на стек их сумму d3
f- (d1 d2 --- d3) Вычитает float-число d2 из float-числа d1 и кладет разность d3 на стек
f* (d1 d2 --- d3) Перемножает двойные числа d1 и d2 в float-формате и кладет на стек произведение d3 в том же формате
f/ (d1 d2 --- d3) Делит float-число d1 на float-число d2 и кладет частное d3 на стек в float-формате
sqr (d1 --- d2) Вычисляет квадратный корень float-числа d1 и кладет результат d2 на стек во float-формате
ln (d1 --- d2) Вычисляет натуральный логарифм float-числа d1 и кладет результат d2 на стек во float-формате
exp (d1 --- d2) Вычисляет показательную функцию float-числа d1 (т.е. e^d1) и кладет результат d2 на стек во float-формате. Значение d1 не должно превышать 71.38013
fnegate (d --- -d) Изменяет знак float-числа в стеке на противоположный
fabs (d --- |d|) Вычисляет и кладет на стек абсолютное значение float-числа d во float-формате
fsign (d --- d n) Кладет на стек код n знака float-числа d: если d>=0, то n=40, иначе n=0
fpor (d --- d n) Кладет на стек порядок n float-числа d без снятия самого числа d со стека
f0= (d --- f) Кладет на стек флаг f: если float-число d равно 0, то f=true, иначе f=false
f0> (d --- f) Кладет на стек флаг f: если float-число d больше 0, то f=true, иначе f=false
f0< (d --- f) Кладет на стек флаг f: если float-число d меньше 0, то f=true, иначе f=false
f> (d1 d2 --- f) Если d1>d2, то f=true, иначе f=false
f< (d1 d2 --- f) Если d1<d2, то f=true, иначе f=false
fc (bld) (d --) Определяющее слово для создания float-константы со значением d. Например, если на стеке лежит число -12.34567e-7 во float-формате, то команда fc bbb создает float-константу bbb со значением -0.1234567e-5. В дальнейшем, при исполнении слова bbb на стек кладется это значение во float-формате
f0 (cnst) (--- d) Кладет на стек число 0 во float-формате
pi (cnst) (--- d) Кладет на стек число Пи=3.141593 во float-формате
.нф
.цв
Таблица 6.2. Операции с плавающей точкой над распакованными float-числами
.нф
.кс-5
bfin Ожидает ввода float-числа с клавиатуры и вводит число в буфер buf3 в распакованном виде. При вводе не используется десятичная точка и лидирующие нули. Так например, число -0.0012345e-7 следует вводить как -12345e-14, а число 123.4567 - в виде 1234567e-4
intflo (d A ---) Преобразует двойное целое число d в распакованное float-число и помещает его в буфер A
fval (A A1 --) Преобразует первое вхождение вещественного числа в строке текста A1 в распакованное float-число по адресу A. Формат вещественного числа при этом должен соответствовать формату ввода словом bfin, т.е. не должен включать десятичную точку и лидрующие нули
bf. (asm) (A ---) Выводит распакованное float-число на экран из буфера A
fadd (asm) (---) Суммирует распакованные float-числа, расположенные в буферах buf1 и buf2, и кладет сумму в буфер buf3 в виде распакованного float-числа
fsub (asm) (---) Вычитает распакованные float-числа, расположенные в буферах buf1 и buf2, и кладет разность (buf1)-(buf2) в буфер buf3 в виде распакованного float-числа
fmul (asm) (---) Перемножает распакованные float-числа, расположенные в буферах buf1 и buf2, и кладет произведение в буфер buf3 в виде распакованного float-числа
fdiv (asm) (---) Делит распакованные float-числа, расположенные в буферах buf1 и buf2, и кладет частное (buf1)/(buf2) в буфер buf3 в виде распакованного float-числа
unpack (asm) (d A ---) Распаковывает float-число d в стеке и распакованное число кладет в буфер по адресу A
pack (asm) (A --- d) Упаковывает распакованное число в буфере A и кладет его во float-формате на стек
bf10n* (n A ---) Умножает на 10^n распакованное число в буфере A. Результат остается в том же буфере
bf^ (u ---) Возводит распакованное число в буфере buf3 в положительную целую степень u. Результат остается в том же буфере
bln (---) Вычисляет натуральный логарифм распакованного числа в буфере buf3. Результат формируется в том же буфере
bexp (---) Вычисляет показательную функцию распакованного числа в буфере buf3. Результат формируется в том же буфере
bsqr (---) Вычисляет квадратный корень распакованного числа в буфере buf3. Результат формируется в том же буфере
bfpor (---) Преобразует одно- или двух-значное целое число, хранящееся в переменной por в распакованное float-число в буфере buf2
bf1 (--- A) Распакованная float-константа, равная 1
fract (---) Вычисляет дробную часть распакованного числа в буфере buf3. Результат формируется в том же буфере
buf1, buf2, buf3, buf4 и buf5 (--- A) Системные текстовые переменные длиной по 23 байта, используемые в качестве рабочих буферов для ввода float-числа с клавиатуры (buf3) и операций над распакованными float-числами
move (A1 A2 ---) Пересылает распакованное число из буфера A1 в буфер A2
fvar (bld) Определяющее слово для создания буфера для распакованной float-переменной. Формат команды: fvar ИМЯ. Значение распакованной переменной присваивается словами intflo, fval, unpack или move
bufarray (bld) (u ---) Определяющее слово для создания массива из u текстовых переменных длиной по 13 байт, которые могут служить буферами для распакованных float-чисел с длиной мантиссы до 9 знаков
.нф
В библиотеке принято, что float-число занимает 4 байта и имеет следующий формат:
.кс-4
2-й (старший) байт двойного числа содержит 0 в старшем, седьмом бите, а код знака - в шестом бите: 1 для положительного числа и 0 - для отрицательного. Остальные 5 битов содержат порядок числа плюс смещение, равное &20. Порядком в данной программе называется показатель степени 10, на которую следует умножить мантиссу, чтобы получить значение float-числа.
Остальные 3 байта двойного числа содержат мантиссу float-числа, которая может включать от 1 до 7 десятичных значащих цифр. Переполнение мантиссы и порядка при вводе не контролируется.
.нф
При вводе float-чисел словом floin формат их может быть любым: с десятичной точкой или без нее, с указанием порядка или без указания, признак порядка - букву e - можно набирать как в строчном, так и в заглавном латинских регистрах.
Однозначные мантиссы необходимо вводить с нулем справа, напр. 0.10, или 1.0, или 0.0030 и т.д., иначе возможно неточное исполнение операции с ними.
Выводятся float-числа словом f. всегда в экспоненциаль- ном формате:
1 выводится как 0.1e1
1234567 выводится как 0.1234567e7 и т. д.
Кроме float-формата в библиотеке используются так называемые распакованные float-числа, над которыми выполняются большинство операций. Эти числа размещены в текстовых переменных, называемых здесь буферами.
Структура буфера такая:
.кс-4
нулевой байт - содержит длину мантиссы числа, 1-й байт - код знака числа ( ¤40 или 0), 2-й байт - порядок числа плюс смещение, равное ¤20, 3-й байт - содержит ноль, 4-й и следующие байты - содержат мантиссу, по одной десятичной цифре в байте.
.нф
Обычно мантисса, распакованная из float-формата, включает до 7 значащих цифр, однако при необходимости их число можно увеличить до 9. Чтобы операции выполнялись с такой точностью, следует ввести число 9 в переменную PREC, размещенную по адресу ¤83. Результаты могут быть выведены в стек не более, чем с 7 значащими цифрами, а непосредственно на экран - со всеми 9 знаками, если воспользоаться словом bf.
В библиотеке имеются два вида арифметических операций. В табл.6.4 приведены слова, которые используют float-числа из стека и кладут результат снова в стек. Эти слова удобны при одиночных арифметических операциях. Однако, они выполняются довольно медленно, так как перед выполнением операции аргументы, находящиеся в стеке, вначале распаковываются в системные буферы, в которых затем и выполняется та или иная операция. Полученный результат должен быть упакован из буфера во float-формат, прежде чем снова попадет в стек.
В табл.6.5 собраны слова, которые более удобны при громоздких расчетах, где важна скорость вычисления. Эти слова в качестве аргументов используют уже распакованные числа в системных буферах и результат формируют также в распакованном виде (обычно в buf3). Цепочки арифметических операций с распакованными числами обычно выполняются на порядок быстрее, чем с числами во float-формате.
Для хранения промежуточных результатов можно использовать распакованные переменные, вводимые словами fvar (для одиночной переменной) и bufarray (для массива). В ряде случаев для этой же цели могут пригодиться системные буферы: если не вычисляется квадратный корень, то свободен buf5, а в задачах без логарифмов и экспонент свободен buf4. Пересылку распакованных чисел из буфера в буфер, а также обмен между буферами и рпапакованными переменными обеспечивает словo move. Для обмена со стеком служат слова unpack (распаковка), intflo (перевод из двойного целого с распаковкой) и pack (упаковка).
В библиотеку включены 2 распакованные константы, 0 и 1, которые часто используются в программах. Обратите внимание на то, что в отличие от упакованных распакованные константы при исполнении кладут на стек только адрес своего поля параметров, что удобно для последующей их обработки словами bf., move и pack. К этим константам, как и к переменным, вводимым словом fvar, не применимы оперции Форта ! и @.
Следует также отметить, что распакованные переменные хотя формально и являются текстовыми, но текстовые операции, такие как gets, ¤., ¤! и т.п., к ним не применимы.
В библиотеке предусмотрен контроль выхода значений порядка результата умножения (f*) и деления (f/) чисел во float-формате за пределы -31 .. +31. При обнаружении выхода программа прерывается и выдается сообщение об ошибке "Переполнение". В аналогичных операциях с распакованными числами (fmul и fdiv) такой контроль отсутствует.
В заключении отметим, что float-библиотека содержит еще одно слово, полезное при решении задач с вещественными числами. Это слово fval, которое просматривает текст в памяти, начиная с адреса A1. Найдя в нем вещественное число, fval преобразует его в распакованное float-число и помещает в заданный буфер A. Формат команды: A A1 fval.
Следует иметь в виду, что найденное вещественное число не должно содержать десятичной точки. Оно должно состоять из целочисленной мантиссы (до 7 знаков) и, если требуется, может включать порядок, например, -1234567е-38. Выделять это число в тексте какими-либо разделителями не обязательно. Такой формат, несмотря на отсутствие десятичной точки, позволяет обрабатывать любые вещественные числа, допустимые float-форматом.
[an error occurred while processing this directive]