Особенности вещественных чисел в Delphi - «Неполноценный» Extended
ОГЛАВЛЕНИЕ
«Неполноценный» Extended
Напомню, чуть выше я сказал, что сопроцессор всегда выполняет все операции в формате Extended, оговорившись при этом, что есть исключение, к которому я вернусь чуть позже. Если вы прочитали всё, что было изложено выше, теперь у вас достаточно знаний, чтобы понять, что это за исключение.
У сопроцессора есть специальный двухбайтный регистр, называемый управляющим словом. Установка отдельных битов этого регистра диктует сопроцессору то или иное поведение. Прежде всего, это связано с тем, какие исключения может возбуждать сопроцессор. Другие биты этого регистра отвечают за то, как будут округляться числа, как сопроцессор понимает бесконечность – всё это можно при необходимости узнать из документации Intel. Нас же будут интересовать только два бита из этого слова – восьмой и девятый. Именно они определяют, как будут обрабатываться числа внутри сопроцессора.
Если восьмой бит содержит единицу (так установлено по умолчанию), то десять байт внутренних регистров сопроцессора будут использоваться полностью, и мы получим «полноценный» Extended. Если же этот бит равен нулю, то всё определяется значением бита 9. Если он равен единице, то используются только 53 разряда мантиссы (остальные всегда равны нулю). Если же этот бит равен нулю – только 24 разряда мантиссы. Это увеличивает скорость вычислений, но уменьшает точность. Другими словами, точность работы сопроцессора может быть понижена до типа Double или даже Single. Но это касается только мантиссы, экспонента в любом случае будет содержать 15 бит, так что диапазон типа Extended сохраняется в любом случае.
Для работы с управляющим словом сопроцессора в модуле System описана переменная Default8087CW:Word и процедура Set8087CW(CW:Word). При запуске программы в переменную Default8087CW записывается то управляющее слово, которое установила система при запуске программы. Функция Set8087CW записывает новое значение в управляющее слово. Одновременно это новое значение записывается в переменную Default8087CW.
Такое поведение этой функции не всегда удобно – иногда бывает нужно сохранить старое значение переменной Default8087CW (впрочем, это несложно сделать, заведя дополнительную переменную). С другой стороны, если значение управляющего слова изменить, не используя Set8087CW (а в дальнейшем мы увидим, что такие изменения могут происходить помимо нашей воли), то с помощью функции Default8087CW просто нет возможности узнать текущее значение управляющего слова. В Delphi 6 и выше появилась функция Get8087CW, позволяющая узнать значение именно контрольного слова, а не переменной Default8087CW. В более ранних версиях единственный способ получить значение этого слова – использование ассемблера, тем более что в Delphi нет проблем с ассемблерными вставками.
Установить значение управляющего слова можно с помощью команды FLDCW, прочитать – с помощью FNSTCW. Обе эти команды имеют один аргумент – переменную типа Word. Чтобы, например, установить 53-значную точность, не изменив при этом другие биты управляющего слова, надо выполнить такую последовательность команд:
asmСовременные сопроцессоры обрабатывают числа с такой скоростью, что при обычных вычислениях вряд ли может возникнуть необходимость в ускорении за счёт точности - выигрыш будет ничтожен. Эта возможность используется, в основном, в тех случаях, когда вычисления с плавающей точкой составляют значительную часть программы, а высокая точность не имеет принципиального значения (например, в движках для 3D-игр). Однако забывать об этой особенности работы сопроцессора не стоит, потому что она может преподнести один неприятный сюрприз, о котором чуть позже.
FNSTCW MyCW
AND MyCW,0FCFFh
OR MyCW,200h
FLDCW MyCW
end;