[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]