ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 17

Глава 15. Использование сопроцессора 80x87
В Турбо Паскале вы можете работать с двумя типами чисел - целыми (короткими целыми - Shortint, целыми - Integer, длинными целыми - Longint, целыми длиной в байт - Byte, целыми длиной в слово - Word) и вещественными (вещественными - Real, вещественными од
инарной точности - Single, вещественными двойной точности - Double, повышенной точности - Extended, сложными - Comp). Вещественные числа называют также числами с плавающей точкой (плавающей зяпятой). Для облегчения работы с целыми числами создан процессо
р 8086, но для работы с вещественными числами на этом процессоре затрачивается гораздо больше времени и усилий. Для семейства процессоров 8086 предназначено соответствущее семейство вспомогательных специализированных процессоров для математических вычисл
ений (сопроцессоров) 80x87.
     Процессор 80x87 - это специальный сопроцессор для обработки чисел, который может входить в состав вашего компьютера РС. С помощью него операции с плавающей точкой выполняются очень быстро. Поэтому если вы собираетесь использовать большой объем вычис
лений с плавающей точкой, то вам, вероятно, понадобится сопроцессор. 
     Турбо Паскаль построен таким образом, что он обеспечивает оптимальное выполнение операций с плавающей точкой независимо от наличия сопроцессора 80x87. 
     1. Для программ, работающих на компьютере РС, независимо от того, оснащен он сопроцессором 80x87 или нет, в Турбо Паскале предусмотрено использование вещественных чисел и соответствующая библиотека программ, которые предназначены для выполнения опер
аций с плавающей точкой. Числа вещественного типа занимают 6 байт памяти. При этом обеспечивается представление чисел в диапазоне от 2.9х10^-39 до 1.7х10^38 с 11-12 значащими цифрами. Программы в библиотеке программ для работы с плавающей точкой оптимизи
рованы по скорости и по размеру и используют самые новейшие средства процессора 80x87. 
     2. Если вы пишете программы, использующиеся только на компьютерах, оснащенных сопроцессором 80x87, то вы можете указать Турбо Паскалю на необходимость получения выполняемого кода, в котором используется плата процессора 80x87. Это даст вам возможнос
ть использования четырех дополнительных типов вещественных чисел (одинарной и двойной точности, повышенной точности, сложного типа) и расширенный диапазон представления чисел с плавающей точкой - от 1.9х10^-4951 до 1,1х10^4943 с 19-20 значащими цифрами. 

     С помощью директивы компилятора $N или параметра меню OptionsіCоmpiler (ПараметрыіКомпилятор) 80x87/80287 можно переключаться между различными моделями генерации кода с плавающей точкой. По умолчанию используется состояние {$N-}. В этом состоянии ко
мпилятор использует 6-байтовую библиотеку с плавающей точкой, что позволяет вам работать только с переменными типа Real. В состоянии {$N+} компилятор генерирует код для сопроцессора 80x87, что дает вам дополнительную точность и доступ к 4 дополнительным 
вещественным типам. 
     При компиляции с режимом числовой обработки, то есть с директивой {$N+}, убедитесь, что Windows может найти в вашей системе библиотеку эмуляции Windows 8087 - WIN87EM.DLL. Эта библиотека обеспечивает необходимый интерфейс между сопроцессором 80х87, 
Windows и вашей прикладной программой. Если сопроцессор 80х87 в вашей системе отсутствует, то библиотека WIN87EM.DLL будет эмулировать его программно. Эмуляция существенно замедляет работу по сравнению с реальным сопроцессором 80х87, но обеспечивает выпо
лнение вашей прикладной программы на любой машине. 
     Замечание: Даже при наличии в вашей системе сопроцессора 80х87 для выполнения программ, скомпилированных в состоянии {$N+}, должна присутствовать библиотека эмуляции WIN87EM.DLL. 
     Примечание: Когда вы выполняете компиляцию в режиме кода 80х87 (директива {$N+}), то возвращаемые подпрограммыми модуля Systем (Sqrt, Рi, Sin и т.д.) значения представляют собой не вещественные числа, а числа типа Extended (с повышенной точностью). 

       {$N+}

       begin
         Writeln(Pi);                 { 3.14159265358979E+0000 }
       end.

       {$N-}

       begin
         Writeln(Pi);                 { 3.1415926536E+00 }
       end.

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

     В дополнение к вещественному типу для программ, использующих средства процессора 80x87, предусматривается четыре новых вещественного типа: 
     1. Тип с одинарной точностью Single, представляющий собой наименьший формат, который вы можете использовать для чисел с плавающей точкой. Он занимает 4 байта памяти обеспечивает диапазон представления чисел от 1.5х10^-45 до 3.4х10^48 с 7-8 значащими
 цифрами. 
     2. Тип с двойной точностью Double, занимающий 8 байт памяти и обеспечивающий представление чисел в диапазоне от 5.0х10^-334 до 1.7х10^308 с 15-16 значащими цифрами. 
     3. Тип с повышенной точностью Extended представляет собой наибольший формат представления чисел с плавающей запятой, обеспечиваемый процессором 80x87. Он занимает 10 байт памяти и обеспечивает диапазон представления чисел от 1.9х10^-4952 до 1.1х10^4
932 с 19-20 значащими цифрами. Любые арифметические операции, в которых участвуют числа вещественного типа, выполняются с точностью и диапазоном представления, соответствующими типу с повышенной точностью. 
     4. Числа сложного типа Comp используются для предварительно объединенных значений в 8 байтах памяти, обеспечивая при этом диапазон представления от -2^63+1 до 2 ^63-1, что составляет приблизительно от -9.2х10^18 до 9.2х10^18. Сложный тип можно сравн
ить с длинным целым типом (двойная точность), но он считается вещественным типом, поскольку при операциях с числами этого типа используется сопроцессор 80x87. Сложный тип хорошо подходит для представления значений денежных единиц, представляющих собой со
тни и тысячи, которые используются в прикладных коммерческих программах. 
     Независимо от того, используете вы сопроцессор 80x87 или нет, 6-битовый вещественный тип является допустимым. Таким образом, при переходе к использованию сопроцессора 80 x87 вам не потребуется изменять исходный текст программы, и вы можете использов
ать файлы данных, созданные программами, которые работают с программно обеспечиваемыми операциями с плавающей точкой. 
     Отметим однако, что аппаратные вычисления с переменными вещественного типа выполняются несколько медленнее, чем с переменными другого типа. Это связано с тем, что сопроцессор 80x87 не может непосредственно обрабатывать вещественный формат. Вместо эт
ого, перед выполнением операций, для преобразования вещественных значений в числа с повышенной точностью требуются обращения к библиотечным программам. Если вы заинтересованы в максимальной скорости выполнения и не собираетесь использовать свою программу
 на системах без сопроцессора 80x87, то возможно вы захотите использовать вещественный тип с одинарной точностью, вещественный тип с двойной точностью, вещественный тип с повыщенной точностью и сложный типы явным образом. 
         Арифметические операции с повышенной точностью

     При использовании сопроцессора 80x87 тип с повышенной точностью Extended является основой всех операций с плавающей точкой. В Турбо Паскале тип с повышенной точностью используется для представления всех нецелых числовых констант, а также при вычисле
нии всех выражений нецелого типа. Например, в следующих операциях присваивания все правые части выражений будут вычисляться, как выражения с повышенной точностью, а затем их тип будет преобразован к типу соответствующей левой части: 
      {$N+}
      var
        X, AA, B, C : real;
      begin
        X := (B + Sqrt(B*B - A*C))/A;
      end;

     Турбо Паскаль выполняет вычисления с точностью и диапазоном представления чисел, соответствующими типу с повышенной точностью, без дополнительных усилий программиста. Дополнительная точность приводит к меньшим ошибкам округления, а дополнительный ди
апазон означает, что ситуации переполнения и потери значимости будут встречаться в программах реже. 
     Вы можете обойтись и без дополнительных автоматических возможностей вычислений в повышенной точностью Турбо Паскаля. Например, описать переменные, использующиеся для промежуточных вычислений, как переменные с повышенной точностью. В следующем пример
е вычисляется сумма произведений: 
     var
       Sm : single;
       X,Y array[1..100] of single;
       I : integer;
       T : extended;            { для промежуточных результатов }
     begin
       T := 0.0;
       for I := 1 to 100 do T := T + X[I] * Y[I]
       Sum := T;
     end;

     Если бы переменная T была описана, как переменная с одинарной точностью, то при каждом цикле операции присваивания для переменной T были бы выполнены с ошибкой округления и ограничениями, соответствующими одинарной точности. Но, поскольку переменная
 T является переменной с повышенной точностью, то все ошибки округления (кроме операции, при которой значение переменной T присваивается переменной Suм) имеют ограничения, соответствующие повышенной точности. Меньшие ошибки округления означают более точн
ый результат. 
     Для значений формальных параметров и результата функции вы также можете задать повышенную точность. Это поможет избежать ненужных преобразований типов чисел, приводящих к потере точности. Например: 
     function Area(Radius: extended): extended;
     begin
       Area := Pi * Radius * Radius;
     end;

                  Сравнение вещественных чисел

     Поскольку значения вещественного типа являются приблизительными, результат сравнения значений различного вещественного типа не всегда можно предсказать. Например, если Х - переменная вещественного типа с одинарной точностью, а Y - переменная веществ
енного типа с двойной точностью (Double), то результатом выполнения следующих операторов будет значение False: 
     X := 1/3;
     Y := 1/3;
     Writeln(X = Y);

     Причина этого состоит в том, что Х имеет точность только до 7-8 цифр, а Y - точность до 15-16 цифр, и когда оба значения преобразуются к типу с повышенной точностью, то после первых 7-8 цифр остальные цифры будут различаться. Аналогично, результатом
 выполнения операторов: 
     X := 1/3;
     Writeln(X = 1/3);
 будет значение False, результат 1/3 в операторе Writeln вычисляется с точностью до 20 значащих цифр. 
                Стек вычислений сопроцессора 80x87

     У сопроцессора 80x87 имеется внутренний стек вычислений, который может быть глубиной до восьми уровней. Доступ к значению, находящемуся в стеке сопроцессора 80x87 осуществляется намного быстрее, чем доступ к переменной в памяти, поэтому для достижен
ия максимально возможной производительности в Турбо Паскале внутренний стек сопроцессора 80x87 используется для хранения временных результатов и для передачи параметров процедурам и функциям. 
     Теоретически слишком сложные выражения вещественного типа могут вызвать переполнение стека сопроцессора 80x87. Однако этого не может случиться, поскольку для этого потребовалось бы, чтобы в выражении получалось более восьми промежуточных результатов
. 
     Более весомая опасность таится во вложенных вызовах функций. Если такие конструкции составлены некорректно, то они, вполне вероятно, могут привести к переполнению стека сопроцессора 80x87. 
     Рассмотрим, следующую функцию, в которой с помощью рекурсии вычисляются числа Фибоначчи: 
     function Fib(N: integer): extended;
     begin
       if N = 0 then
          Fib := 0.0
       else
         if N = 1 then
            Fib := 1.0
         else
       Fib := Fib(N-1) + Fib(N-2);
     end;

     Обращение к данной версии процедуры Fib приведет к переполнению стека сопроцессора 80x87, так как значений N больше, чем 8. Причина заключается в том, что последний оператор присваивания требует временного сохранения результата выполнения процедуры 
Fib (N-1) в стеке сопроцессора 80x87. Каждое рекурсивное обращение выделяется одна ячейка стека и на девятом обращении произойдет переполнение стека. Корректной конструкцией в этом случае будет: 
     function Fib(N : integer) : extended;
     var
       F1,F2 : Extended;
     begin
       if N = 0 then
              Fib := 0.0
          else
            if N = 1
               then Fib := 1.0
            else
              begin
                 F1 := Fib(N-1); F2 := Fib(N-2);
                 Fib := F1 + F2;
              end;
     end;

     Временные результаты теперь сохраняются в переменных, для которых отводится стек процессора 8086. (Стек процессора 8086 конечно тоже может переполниться, но это обычно требует гораздо большего числа рекурсивных вызовов). 
  Запись вещественных чисел при использовании сопроцессора 80x87

     Если была указана директива {$N+}, то стандартные процедуры Write и Writeln, чтобы обеспечить представление в расширенном диапазоне, выводят в строке с десятичными числами с плавающей точкой четыре цифры для показателя степени вместо двух. Аналогичн
о, стандартная процедура Str при выборе формата с плавающей точкой возвращает значение показателя степени, состоящее из четырех цифр. 
         Модули, в которых используется сопроцессор 80x87

     Модули, в которых используется сопроцессор 80x87, могут вызываться другими модулями или программами только в том случае, если эти модули или программы были скомпилированы с директивой {$N+}. То, что модуль использует сопроцессор 80x87, определяется 
наличием в нем инструкций сопроцессора 80x87, а не директивой $N во время компиляции. Это позволяет компилятору быть более "снисходительным", когда вы случайно компилируете модуль (в котором используется сопроцессор 80x87), не указав директиву {$N+}. 
     Примечание: Когда вы выполняете компиляцию в режиме кода 80х87 (директива {$N+}), то возвращаемые подпрограммыми модуля Systем (Sqrt, Рi, Sin и т.д.) значения представляют собой не вещественные числа, а числа типа Extended (с повышенной точностью). 

                 Распознавание сопроцессора 80x87

     Операционная среда Windows и библиотека эмуляцмм WIN87EM.DLL автоматически распознает наличие в системе платы сопроцессора 80x87. Если сопроцессор 80x87 имеется, то программа будет его автоматически использовать. В случае же его отсутствия программа
 будет использовать эмуляцию с помощью WIn87EM.DLL. Чтобы определить наличие в системе сопроцессора 80х87, вы можете использовать функцию GetWinFlags (которая определена в модуле WinProcs) и битовую маску wf_80x87 (определенную в модуле WinTypes). Наприм
ер: 
     if GetWinFlags and wf_80x87 <> 0 then
         Writeln('80x87 присутствует') else
         Writeln('80x87 отсутствует');

  Использование эмуляции сопроцессора 80x87 на языке Ассемблера

     Когда компоновка объектных файлов выполняется с директивой {$L имя_файла}, необходимо обеспечить, чтобы эти файлы компилировалить с разрешением эмуляции сопроцессора 80x87. Например, если вы используете инструкции сопроцессора 80x87 во внешних проце
дурах на языке ассемблера, необходимо убедиться, что при ассемблировании файлов .ASM в файлы .OBJ эмуляция разрешена. В противном случае инструкции сопроцессора 80x87 не могут эмулироваться на машинах без сопроцессора 80x87. Для разрешения эмуляции испол
ьзуйте параметр командной строки Турбо Ассемблера /E. 


Яндекс цитирования