Раздел 2. Арифметический процессор
Реализация алгоритмов, в которых необходима высокая точность вычислений, наталкивается на трудности, связанные с недостаточной разрядностью представимых данных. Кроме того, в системе команд ЦП отсутствуют операции с данными, представленными с плавающей запятой, что затрудняет обработку чисел, изменяющихся в широком диапазоне. Для увеличения разрядности данных и выполнения арифметических операций с плавающей запятой можно составить соответствующие подпрограммы, однако их выполнение будет занимать значительное время. Более эффективным является использование специальных аппаратных средств. К таким средствам относится арифметический процессор (АП) Intel 8087, который называют специализированным сопроцессором для выполнения арифметических операций над числами с плавающей запятой. АП позволяет работать с тремя типами данных; целыми числами, представленными в двоичной системе счисления; целыми числами, представленными в двоично-десятичной системе счисления; вещественными числами.
Двоичные целые числа. Могут быть представлены в одном из трех форматов: слово (16-разрядное число со знаком), короткое целое (32-разрядное число со знаком) и длинное целое (64-разрядное число со знаком). В памяти целые двоичные числа записываются начиная с младшего байта.
Порядок
Мантисса
31
23
0
79
64
0
ВВФ
Порядок
Мантисса
Двоично-десятичное представление чисел. Соответствует формату, показанному на рис. 2.1, а, где d17 – d0 — обозначают 4-разрядные коды цифр числа. Таким образом, максимальное число значащих разрядов равно 18. Для записи двоично-десятичных чисел в памяти отводится 10 байт.
Старший байт (на рисунке разряды 72 — 79) содержит только знак числа в старшем бите, а остальные его разряды не используются.Вещественные числа. Могут быть представлены в одном из трех форматов. Короткий вещественный формат (КВФ) занимает 32 двоичных разряда и состоит из 23-разрядной мантиссы, 8-разрядного порядка и знака мантиссы. Длинный вещественный формат (ДВФ) занимает 64 двоичных разряда и состоит из 52-разрядной мантиссы, 11-разрядного порядка и знака мантиссы. Внутренний вещественный формат (ВВФ) занимает 80 двоичных разрядов и состоит из 64-разрядной мантиссы, 15-разрядного порядка и знака мантиссы. Все форматы вещественных чисел соответствуют стандарту IEEE 754.
Диапазон значений вещественных чисел с плавающей запятой, в котором могут выполняться вычисления арифметическим процессором, приведен в табл. 4.1
Способ записи мантиссы и порядка вещественных чисел имеет следующие особенности. Числа представляются в нормализованном виде, т. е. первая значащая цифра после запятой не нуль. Например, нормализованный вид десятичного числа 0,0057 есть 0,57*10-2.
Таблица 2.1
Диапазоны представлений | Диапазоны значений | ||||
Знак | Порядок | Мантисса | КВФ | ДВФ | ВВФ |
1 | 1 1 . .. 1 1 | 1 1 … 1 1 | NAN | NAN | NAN |
. . . | . . . | . . . | . . . | . . . | |
1 | 1 1 … 1 1 | 00…01 | NAN | NAN | |
1 | 1 1 … 1 1 | 00. ..00 | — оо | — оо | — оо |
1 | 11…10 | 11…11 | — 3,37*1038 | — 1,67*10308 | — 1,2*104932 |
. . . | . . . | . . . | . . . | . . . | |
1 | 00…00 | 00…01 | — 8,43*10-37 | — 4,19*10-307 | — 3,4*10-4931 |
1 | 00. ..00 | 00…00 | — 0 | — 0 | — 0 |
0 | 00…00 | +0 | +0 | +0 | |
0 | 00…00 | 00…01 | + 8,43*10-37 | + 4,19*10-307 | + 3,4*10-4931 |
. . . | . . . | . . . | . . . | . . . | |
0 | 1 1 … 1 0 | 1 1 … 1 1 | + 3,37*1038 | + 1,67*10308 | + 1,2*104932 |
0 | 1 1 … 1 1 | 00…00 | + оо | +оо | +оо |
0 | 1 1 … 1 1 | 00…01 | NAN | NAN | NAN |
. . . | . . . | . . . | . . . | . . . | |
0 | 11…11 | 11…11 | NAN | NAN | NAN |
Порядки всегда суммируются с константой смещения, выбранной так, что максимальное отрицательное значение порядка, будучи просуммировано с этой константой, дает в результате нуль. Константы смещения имеют различные значения для каждого формата вещественных чисел: КВФ — 127, ДВФ — 1023 и ВВФ — 16383.
Схема АП (рис. 2.2) включает два основных блока — сопряжения с шиной (БСШ) и исполнительный ИБ. Эти блоки, как и в ЦП, осуществляют конвейерный принцип обработки данных, при котором извлечение команд и операндов выполняется параллельно с вычислениями. Команды и операнды по мультиплексированной шине адреса/данных (ША/Д) ВМ, предварительно извлекаются из памяти и размещаются в соответствующих очередях. АП может работать только в паре с центральным процессором, который в этом случае должен быть установлен в максимальный режим. Когда процессоры включены совместно, команды передаваемые по ША/Д, поступают на оба процессора одновременно. В то время как ЦП выполняет команды, АП просто «прослеживает» их прохождение, не выполняя никаких действий.
ю
Рис. 2.2. Архитектура арифметического процессора Intel 8087
Это пассивное «прослеживание» продолжается до тех пор, пока в потоке команд не встречается команда ESC, которая предназначена для АП. С момента поступления команды ESC арифметический процессор начинает анализировать состояние очереди команд ЦП по сигналам QS1, QS0 (табл. 2.2). Поскольку команды в ЦП хранятся в очереди байтов команд, точный момент начала выполнения команды ESC определяется по концу выполнения предыдущей команды в очереди.
Таблица 2.2
Состояние очереди команд | Действия с очередью команд в ЦП | |
QS0 | QS1 | |
0 | 0 | Очередь не изменилась |
0 | 1 | Первый байт команды взят из очереди |
1 | 0 | Очередь реинициализирована |
1 | 1 | Очередной байт команды взят из очереди |
Как только сопроцессор определит, что последний байт предыдущей (перед ЕSС) команды взят из очереди, он приступает к выполнению своей команды. Команда ESC, как было отмечено в 1.9, обычно предваряется командой WAIT, которая переводит ЦП в состояние ожидания. Время нахождения центрального процессора в состоянии ожидания определяется активным сигналом на входе TEST. Арифметический процессор, приступая к выполнению команды, выставляет на выходе BUSY (занят) единичный сигнал, который подается на вход TEST центрального процессора и задерживает его в состоянии ожидания на время выполнения команды.
Напомним, что, находясь в состоянии ожидания, ЦП анализирует запросы прерывания и при необходимости может их обслуживать. Для обеспечения возможности совместного использования ША/Д процессоры снабжены соответствующими аппаратными средствами. Центральный процессор обладает преимущественным правом использования шины. Когда у АП возникает необходимость использования шины, например при пересылке результата операции в память, он посылает запрос на предоставление шины центральному процессору по линии RQ/GT. ЦП по этой же линии выдает сигнал разрешения на использование шины арифметическому процессору. После того как АП выполнит действия, связанные с использованием шины, он вновь посылает сигнал по линии RQ/GT, свидетельствующий об окончании использования. Этот механизм позволяет синхронизировать работу процессоров, предоставляя ресурсы ВМ в распоряжение АП.
Закончив выполнение команды, АП сбрасывает сигнал BUSY, делая активным сигнал на входе TEST, и выводит ЦП из состояния ожидания. Из приведенного описания ясно, что побудительным стимулом для включения в работу сопроцессора является наличие кода команды ESC в потоке команд совместно включенных процессоров. Код операции, которую выполняет АП, содержится в полях Х и Y команды ESC (см. рис. 1.9). В ряде случаев при выполнении команд в АП возникают исключительные ситуации, связанные с переполнением, потерей точности при округлениях и т. п. Для обработки таких ситуаций может потребоваться вмешательство ЦП, которому предписаны соответствующие программы обработки исключительных ситуаций. Механизм передачи управления на эти программы основан на использовании системы прерываний. Для этой цели АП имеет выход INT запроса прерываний, на котором генерируется сигнал запроса, когда возникает та или иная исключительная ситуация.
Рассмотренные аппаратные и программные средства процессоров позволяют достаточно просто организовать их взаимодействие и значительно расширить возможности ЦП.
Виды двоичных кодов
В микропроцессорах двоичные коды используются для представления любой обрабатываемой информации. При этом разрядность обрабатываемых чисел может превышать разрядность самого процессора и используемой в нЈм памяти. В этом случае длинное число может занимать несколько ячеек памяти и обрабатываться несколькими командами процессора. При обработке все ячейки памяти, выделенные под многобайтное число, рассматриваются как одно число.
Для представления числовой информации могут использоваться знаковые и беззнаковые коды. Для определЈнности примем длину слова процессора равной восьми битам.
Беззнаковые двоичные коды.
Первый вид двоичных кодов, который мы рассмотрим — это целые беззнаковые коды. В этих кодах каждый двоичный разряд представляет собой степень цифры 2:
При этом минимально возможное число, которое можно записать таким двоичным кодом, равно 0. Максимально возможное число, которое можно записать таким двоичным кодом, можно определить как:
Этими двумя числами полностью можно определить диапазон, чисел которые можно представить таким двоичным кодом. В случае двоичного восьмиразрядного беззнакового целого числа диапазон будет: диапазон чисел, которые можно записать таким кодом: 0 .. 255. Для шестнадцатиразрядного кода этот 0 .. 65535. В восьмиразрядном процессоре для хранения такого числа используется две ячейки памяти, расположенные в соседних адресах. Для работы с такими числами используются специальные команды.
Второй вид двоичных кодов, который мы рассмотрим — это прямые целые знаковые коды. В этих кодах старший разряд в слове используется для представления знака числа. В прямом знаковом коде нулем обозначается знак ‘+’, а единицей — знак ‘-‘. В результате введения знакового разряда диапазон чисел смещается в сторону отрицательных чисел:
В случае двоичного восьмиразрядного знакового целого числа диапазон чисел, которые можно записать таким кодом: -127 .. +127. Для шестнадцатиразрядного кода этот диапазон будет: -32767 .. +32767. В восьмиразрядном процессоре для хранения такого числа тоже используется две ячейки памяти, расположенные в соседних адресах.
Недостатком такого кода является то, что знаковый разряд и цифровые разряды приходится обрабатывать раздельно. Алгоритм программ, работающий с такими кодами получается сложный. Для выделения и изменения знакового разряда приходится применять механизм маскирования разрядов, что резко увеличивает размер программы и уменьшает ее быстродействие. Для того, чтобы алгоритм обработки знакового и цифровых разрядов не различался, были введены обратные двоичные коды.
Знаковые обратные двоичные коды.
Обратные двоичные коды отличаются от прямых только тем, что отрицательные числа в них получаются инвертированием всех разрядов числа. При этом знаковый и цифровые разряды не различаются. Алгоритм работы с такими кодами резко упрощается.
Тем не менее при работе с обратными кодами требуется специальный алгоритм распознавания знака, вычисления абсолютного значения числа, восстановления знака результата числа. Кроме того, в прямом и обратном коде числа для запоминания числа 0 используется два кода, тогда как известно, что число 0 положительное и отрицательным не может быть никогда.
Знаковые дополнительные двоичные коды.
От перечисленных недостатков свободны дополнительные коды. Эти коды позволяют непосредственно суммировать положительные и отрицательные числа не анализируя знаковый разряд и при этом получать правильный результат. Все это становится возможным благодаря тому, что дополнительные числа являются естественным кольцом чисел, а не исскуственным образованием как прямые и обратные коды. Кроме того немаловажным является то, что вычислять дополнение в двоичном коде чрезвычайно легко. Для этого достаточно к обратному коду добавить 1:
Диапазон чисел, которые можно записать таким кодом: -128 .. +127. Для шестнадцатиразрядного кода этот диапазон будет: -32768 .. +32767. В восьмиразрядном процессоре для хранения такого числа используется две ячейки памяти, расположенные в соседних адресах.
В обратных и дополнительных кодах наблюдается интересный эффект, который называется эффект распространения знака. Он заключается в том, что при преобразовании однобайтного числа в двухбайтное достаточно всем битам старшего байта присвоить значение знакового бита младшего байта. То есть для хранения знака числа можно использовать сколько угодно старших бит. При этом значение кода совершенно не изменяется.
Использование для представления знака числа двух бит предоставляет интересную возможность контролировать переполнения при выполнении арифметических операций. Рассмотрим несколько примеров.
1) Просуммируем числа 12 и 5
В этом примере видно, что в результате суммирования получается правильный результат. Это можно проконтролировать по флагу переноса C, который совпадает со знаком результата (действует эффект распространения знака).
2) Просуммируем два отрицательных числа -12 и -5
В этом примере флаг переноса C тоже совпадает со знаком результата, то есть переполнения не произошло и в этом случае
3) Просуммируем положительное и отрицательное число -12 и +5
В этом примере при суммировании положительного и отрицательного числа автоматически получается правильный знак результата. В данном случае знак результата отрицательный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было (мы можем убедиться в этом непосредственными вычислениями на бумаге или на калькуляторе).
4) Просуммируем положительное и отрицательное число +12 и -5
В данном примере знак результата положительный. Флаг переноса совпадает со знаком результата, поэтому переполнения не было и в этом случае.
5)Просуммируем числа 100 и 31
В этом примере видно, что в результате суммирования произошло переполнение восьмибитовой переменной, т.к. в результате операции над положительными числами получился отрицательный результат. Однако если рассмотреть флаг переноса, то он не совпадает со знаком результата. Эта ситуации является признаком переполнения результата и легко обнаруживается при помощи операции «исключающее ИЛИ» над старшим битом результата и флагом переноса C. Большинство процессоров осуществляют эту операцию аппаратно и помещают результат во флаг переполнения OV.
В этом примере результате операции над отрицательными числами в результате суммирования произошло переполнение восьмибитовой переменной, т.к. получился положительный результат. И в этом случае если рассмотреть флаг переноса C, то он не совпадает со знаком результата. Отличие от предыдущего случая только в комбинации этих бит. В примере 5 говорят о переполнении результата (комбинация 01), а в примере 6 об антипереполнении результата (комбинация 10).
Представление дробных чисел в двоичном коде с фиксированной запятой.
Кроме целых чисел часто требуется работать с дробными числами. Следующий вид двоичных кодов, который мы рассмотрим — это дробные коды. Как и в случае целых чисел, дробные числа могут быть беззнаковые и знаковые. Для записи знаковых чисел могут быть использованы прямые, обратные и дополнительные коды. Принцип их построения точно такой же, как и в случае целых чисел.
Рассмотрим, как можно записать дробное число. До сих пор мы предполагали, что двоичная запятая находится правее самого младшего разряда. Но кто сказал, что она должна всегда находиться в этом месте? Мы можем договориться, что запятая находится слева от самого старшего разряда, и тогда в такой переменной можно будет записывать только дробные числа:
Или договоримся, что она находится точно посередине переменной, и тогда мы сможем записывать смешанные числа:
Остальные случаи рассматривать не будем. Они строятся точно так же как и для целых чисел.
Представление чисел в двоичном коде с плавающей запятой.
Часто приходится обрабатывать очень большие числа (например, расстояние между звЈздами) или наоборот очень маленькие числа (например, размеры атомов или электронов). При таких вычислениях пришлось бы использовать числа с очень большой разрядностью. В то же время нам не нужно знать расстояние между звЈздами с точностью до миллиметра. Для вычислений с такими величинами числа с фиксированной запятой неэффективны.
В десятичной арифметике для записи таких чисел используется алгебраическая форма. При этом число записывается в виде мантиссы, умноженной на 10 в степени, отображающей порядок числа, Например:
0,2*105; 0,16*10-38
Для записи двоичных чисел тоже используется такая форма записи. Эта форма записи называется запись числа с плавающей точкой. Напомним, что мантисса не может быть больше единицы и после запятой в мантиссе не может записываться ноль.
А теперь рассмотрим промышленные стандарты, используемые для представления чисел в компьютерах. Существует стандарт IEEE 754 для представления чисел с одинарной точностью (float) и с двойной точностью (double). Для записи числа в формате с плавающей запятой одинарной точности требуется тридцатидвухбитовое слово. Для записи чисел с двойной точностью требуется шестидесятичетырЈхбитовое слово. Чаще всего числа хранятся в нескольких соседних ячейках памяти процессора. Форматы числа в формате с плавающей запятой одинарной точности и числа в формате с плавающей запятой удвоенной точности приведены на рисунке
На рисунке буквой S обозначен знак числа, 0 — это положительное число, 1 — отрицательное число. e обозначает смещЈнный порядок числа. Смещение требуется, чтобы не вводить в число еще один знак. СмещЈнный порядок всегда положительное число. Для одинарной точности для порядка выделено восемь бит. Для смещЈнного порядка двойной точности отводится 11 бит. Для одинарной точности смещение принято 127, а для двойной точности — 1023. В десятичной мантиссе после запятой могут присутствовать цифры 1:9, а в двоичной — только 1. Поэтому для хранения единицы после двоичной запятой не выделяется отдельный бит в числе с плавающей запятой. Единица подразумевается, как и двоичная запятая. Кроме того, в формате чисел с плавающей запятой принято, что мантисса всегда больше 1. То есть диапазон значений мантиссы лежит в диапазоне от 1 до 2.
Рассмотрим несколько примеров:
1) Определить число с плавающей запятой, лежащее в четырЈх соседних байтах:
11000001 01001000 00000000 00000000
— Знаковый бит, равный 1 показывает, что число отрицательное.
— Экспонента 10000010 в десятичном виде соответствует числу 130. Вычтя число 127 из 130, получим число 3.
— Теперь запишем мантиссу: 1,100 1000 0000 0000 0000 0000
— И, наконец, определим десятичное число: 1100,1b = 12,5d
2) Определить число с плавающей запятой, лежащее в четырЈх соседних байтах:
11000011 00110100 00000000 00000000
— Знаковый бит, равный 1 показывает, что число отрицательное.
— Экспонента 10000110 в десятичном виде соответствует числу 134. Вычтя число 127 из 134, получим число 7.
— Теперь запишем мантиссу: 1,011 0100 0000 0000 0000 0000
— И, наконец, определим десятичное число: 10110100b=180d
Для того чтобы записать ноль, достаточно записать в смещенный порядок число 00000000b. Значение мантиссы при этом не имеет значения. Число, в котором все байты равны 0, тоже попадает в этот диапазон значений.
Бесконечность соответствует смещенному порядку 11111111b и мантиссе, равной 1,0. При этом существует минус бесконечность и плюс бесконечность (переполнение и антипереполнение), которые часто отображаются на экран монитора как +INF и -INF.
Все остальные комбинации битов (в том числе и все единицы) воспринимаются как не числа и отображаются на экран: NaN.
Запись десятичных чисел.
Иногда бывает удобно хранить числа в памяти процессора в десятичном виде (Например, для вывода на экран дисплея). Для записи таких чисел используются двоично-десятичные коды. Для записи одного десятичного разряда используется четыре двоичных бита. Эти четыре бита называются тетрадой. Иногда встречается название, пришедшее из англоязычной литературы: нибл. При помощи четырех бит можно закодировать шестнадцать цифр. Лишние комбинации в двоично-десятичном коде являются запрещенными. Таблица соответствия двоично-десятичного кода и десятичных цифр приведена ниже:
Остальные комбинации двоичного кода в тетраде являются запрещенными. Запишем пример двоично-десятичного кода:
1258 = 0001 0010 0101 1000
589 = 0000 0101 1000 1001
Достаточно часто в памяти процессора для хранения одной десятичной цифры выделяется одна ячейка памяти (восьми, шестнадцати или тридцатидвухразрядная). Это делается для повышения скорости работы программы. Для того, чтобы отличить такой способ записи двоично-десятичного числа от стандартного, способ записи десятичного числа, как это показано в примере, называется упакованной формой двоично-десятичного числа.
Суммирование двоично-десятичных чисел.
Суммирование двоично-десяичных чисел можно производить по правилам обычной двоичной арифметики, а затем производить двоично-десятичную коррекцию. Двоично-десятичная коррекция заключается в проверке каждой тетрады на допустимые коды. Если в какой либо тетраде обнаруживается запрещенная комбинация , то это говорит о переполнении. В этом случае необходимо произвести двоично-десятичную коррекцию. Двоично-десятичная коррекция заключается в дополнительном суммировании числа шесть (число запрещенных комбинаций) с тетрадой, в которой произошло переполнение или произошЈл перенос в старшую тетраду. ПриведЈм два примера:
Запись текстов в памяти процессора.
Все символы и буквы могут быть закодированы при помощи восьми двоичных символов. Наиболее распространенными таблицами являются таблицы ASCII с национальными расширениями, применяющиеся в DOS (и которые можно использовать для записи текстов в микропроцессорах), и таблицы ANSI, применяющиеся в WINDOWS. В таблицах ASCII и ANSI первые 128 символов совпадают. В этой части таблицы содержатся символы цифр, знаков препинания, латинские буквы верхнего и нижнего регистров и управляющие символы. Национальные расширения символьных таблиц и символы псевдографики содержатся в последних 128 кодах этих таблиц, поэтому русские тексты в операционных системах DOS и WINDOWS не совпадают.
[Назад] [Содержание] [Вперёд]
математика — Что такое NaN (не число) словами новичка?
Вы задали здесь ряд отличных вопросов. Вот моя попытка обратиться к каждому из них.
Что такое значение NaN или именно NaN (по словам профессора, не являющегося математиком)?
Предположим, вы работаете с действительными числами — такими, как 1, π, e, -137, 6,626 и т. д. В стране действительных чисел есть некоторые операции, которые можно выполнить обычно , но иногда нельзя. t иметь определенный результат. Например, давайте посмотрим на логарифмы. Вы можете логарифмировать множество действительных чисел: например, ln e = 1, а ln 10 равно примерно 2,3. Однако математически логарифм отрицательного числа не определен. То есть мы не можем взять ln (-4) и получить обратно действительное число.
Итак, давайте перейдем к программированию. Представьте, что вы пишете программу, которая вычисляет логарифм числа, и каким-то образом пользователь хочет, чтобы вы разделили на логарифм отрицательного числа. Что должно произойти?
На этот вопрос есть множество разумных ответов. Вы можете сделать так, чтобы операция выдавала исключение, что делается в некоторых языках, таких как Python.
Однако на уровне аппаратного обеспечения было принято решение (людьми, разработавшими стандарт IEEE-754) предоставить программисту второй вариант. Вместо того, чтобы сбой программы, вы можете вместо этого сделать так, чтобы операция выдавала значение, которое означает «вы хотели, чтобы я сделал что-то невозможное, поэтому я сообщаю об ошибке». Это делается так: операция производит специальное значение 9.0017 NaN («Не число»), указывающее, что где-то в ваших вычислениях вы пытались выполнить операцию, которая математически не определена.
Этот подход имеет некоторые преимущества. Во многих условиях научных вычислений код выполняет серию длинных вычислений, периодически генерируя промежуточные результаты, которые могут представлять интерес. Имея операции, которые не определены, производят NaN
в результате, программист может написать код, который просто выполняет математику так, как он хочет, а затем вводит определенные места в код, где они будут проверять, была ли операция успешной. или не. Оттуда они могут решить, что делать. Сравните это с отключением исключения или полным сбоем программы — это означало бы, что программист должен либо охранять каждую серию операций с плавающей запятой, которые могут завершиться ошибкой, либо должен сам вручную тестировать вещи. Это вопрос суждения о том, какой вариант лучше, поэтому вы можете включить или отключить поведение NaN с плавающей запятой.
Какие операции вызывают в результате значение NaN?
Есть много способов получить результат операции NaN
. Вот образец, хотя это не исчерпывающий список:
- Получение журнала отрицательного числа.
- Извлечение квадратного корня из отрицательного числа.
- Вычитание бесконечности из бесконечности.
- Выполнение любой арифметической операции над
NaN
.
Однако некоторые операции не производят NaN
, даже если они математически не определены. Например, деление положительного числа на ноль дает в результате положительную бесконечность, хотя это и не определено математически. Причина этого в том, что если вы берете предел x / y для положительного x, когда y приближается к нулю с положительного направления, значение неограниченно растет.
Почему результат 0.0/0.0 объявлен как неопределенный? Разве это не должно быть 0?
Это больше математический вопрос, чем что-либо еще. Это связано с тем, как работают лимиты. Давайте подумаем, как определить 0 / 0. Один из вариантов — сказать следующее: если мы посмотрим на выражение 0 / x и возьмем предел, когда x приближается к нулю, то мы увидим 0 в каждой точке, поэтому предел должно быть равно нулю. С другой стороны, если мы посмотрим на выражение x / x и возьмем предел, когда x приближается к 0, мы увидим 1 в каждой точке, поэтому предел должен быть равен единице. Это проблематично, так как мы хотели бы, чтобы значение 0 / 0 соответствовало тому, что вы обнаружите при оценке любого из этих выражений, но мы не можем выбрать фиксированное значение, которое имеет смысл. В результате значение 0/0 оценивается как NaN
, что указывает на то, что здесь нет четкого значения для назначения.
Почему результат любой математической операции не может быть выражен числом с плавающей запятой или целым числом? Как может быть, что ценность непредставима?
Это связано с внутренним устройством чисел с плавающей запятой IEEE-754. Интуитивно это сводится к тому простому факту, что
- существует бесконечно много действительных чисел, бесконечно многие из которых имеют бесконечно длинные неповторяющиеся десятичные дроби, но
- у вашего компьютера конечная память.
В результате сохранение произвольного действительного числа может повлечь за собой хранение бесконечно длинной последовательности цифр, чего мы не можем сделать на наших компьютерах с конечной памятью. Таким образом, у нас есть числа с плавающей запятой, хранящие приближений действительных чисел , которые не являются ошеломляюще огромными , а невозможность представления значений возникает из-за того, что мы просто храним приближения.
Чтобы узнать больше о том, как на самом деле хранятся числа и что это означает на практике, ознакомьтесь с легендарным руководством «Что должен знать каждый программист об арифметике с плавающей запятой»
Почему квадратный корень из отрицательного числа не является действительным числом?
Возьмем, например, √(-1). Представьте, что это действительное число x; то есть представьте, что x = √(-1). Идея квадратного корня заключается в том, что это число, которое при умножении само на себя возвращает число, из которого вы извлекли квадратный корень.
Итак… какое число равно х? Мы знаем, что x ≠ 0, потому что 0 2 = 0 не равно -1. Мы также знаем, что x не может быть положительным, потому что любое положительное число, умноженное на себя, является положительным числом. А мы и знают, что x не может быть отрицательным, потому что любое отрицательное число, умноженное на себя, является положительным.
Теперь у нас проблема. Чем бы ни был этот x, он должен быть не положительным, не нулевым и не отрицательным. Это означает, что это не настоящее число.
Вы можете обобщить вещественные числа до комплексных, введя число i, где i 2 = -1. Обратите внимание, что никакие действительные числа не делают этого по причине, указанной выше.
Почему NaN не эквивалентен неопределенности?
Есть разница между «неопределенный» и «что бы это ни было, это не настоящее число». Например, 0/0 можно назвать неопределенным, потому что в зависимости от того, как вы приближаетесь к 0/0, вы можете получить обратно 0, или 1, или, возможно, что-то еще. С другой стороны, √(-1) совершенно точно определяется как комплексное число (при условии, что √(-1) возвращает i, а не -i), поэтому проблема не в том, что «это неопределенно», а в большей степени. как «у него есть значение, но это значение не является реальным числом».
Надеюсь, это поможет!
с плавающей запятой — Вопросы по операциям с NaN
спросил
Изменено 6 лет, 7 месяцев назад
Просмотрено 1к раз
Мой SSE-FPU генерирует следующие значения NaN:
- Когда я выполняю любую базовую двойную операцию, такую как ADDSD, SUBSD, MULSD или DIVSD, и один из обоих операндов является NaN, результат имеет знак NaN-операнда и младшие 51 бит мантиссы результата загружаются младшими 51 битами мантиссы NaN-операнда.
- Если обе операции имеют значение NaN, результат загружается со знаком регистра назначения, а младшие 51 бит мантиссы результата загружаются с младшими 51 битами регистра назначения перед операцией. Таким образом, ассоциативный закон не учитывается при умножении двух NaN-операндов!
- Когда я выполняю SQRTSD для значения NaN, результат имеет знак NaN-операнда, и младшие 51 бит результата загружаются с младшими 51 битами операнда.
- Когда я делаю умножение бесконечности на ноль или бесконечность, я всегда получаю в результате -NaN (двоичное представление 0xFFF8000000000000u).
- Если какой-либо операнд является сигнальным NaN, результатом становится тихий NaN, если исключение не замаскировано.
Определяется ли такое поведение где-либо в стандарте IEEE-754?
- с плавающей запятой
- x86
- sse
- nan
- ieee-754
2
NaN имеют знак и полезную нагрузку , вместе называемые информацией , содержащейся в NaN .
Весь смысл NaN в том, что они «липкие» (может быть, Monadic — лучший термин?), как только у нас есть NaN в выражении, все выражение оценивается как NaN.
Также значения NaN обрабатываются особым образом при оценке предикатов (например, бинарных отношений), например, если a
равно NaN, то оно не равно самому себе.
Точка 1
Из IEEE 754:
Распространение диагностической информации требует, чтобы эта информация содержащиеся в NaN, должны быть сохранены с помощью арифметических операций и преобразования формата с плавающей запятой.
Пункт 2
Из IEEE 754:
Каждая операция, включающая один или два входных NaN, ни один из которых не сигнализирует, не должен сигнализировать об исключении, но, если должен быть доставлен результат с плавающей запятой, должен предоставить в качестве результата тихий NaN, который должен быть одним из входных NaNs.
Ни одна операция с плавающей запятой никогда не была ассоциативной.
Я думаю, что вы искали термин коммутативный хотя, поскольку ассоциативность требует участия по крайней мере трех операндов.
Пункт 3
См. пункт 4
Пункт 4
Из IEEE 754:
Недействительными операциями являются
1. Любая операция над сигнальным NaN (6.2)
2. Сложение или вычитание – вычитание величины бесконечности, например, (+БЕСКОНЕЧНОСТЬ) + (–БЕСКОНЕЧНОСТЬ)
3. Умножение – 0 × БЕСКОНЕЧНОСТЬ
4. Деление – 0/0 или БЕСКОНЕЧНОСТЬ/БЕСКОНЕЧНОСТЬ
5. Остаток – x REM y, где y равно нулю или x бесконечно
6. Квадратный корень, если операнд меньше нуля
7. Преобразование двоичного числа с плавающей запятой в целое или десятичный формат, когда переполнение, бесконечность или NaN исключают верный представление в этом формате, и иначе это не может быть сигнализировано
8.