Pull to refresh
0
0
Спиридонов Юрий Маркович @Innotor

Изобретатель

Send message
Денормализованные, или субнормальные числа в IEEE отнесены к особому случаю и обрабатываются по особым алгоритмам. И алгоритмы эти в сопроцессоре существенно отличаются от работы с нормализованными числами.
Для программиста, с точки зрения написания кода, это видимо не сильно заметно.
Но согласно данным, приведенным в работе. charm.cs.illinois.edu/newPapers/06-13/paper.pdf (См. TABLE II
WORST CASE SLOWDOWNS ON OUR SUBNORMAL SLOWDOWN
MICRO-BENCHMARK ON COMMON MICRO-ARCHITECTURES) использование денормализованных чисел существенно замедляет работу процессора. А там, где она сведена к минимуму, это достигается большими аппаратными затратами.
Проверил. Эта ссылка открывается yadi.sk/i/UYfZjfNakwFoM
Текст в PDF можно посмотреть по ссылке yadi.sk/i/UYfZjfNakwFoM
Спасибо, я так и попробую сделать. Ссылку предоставлю.
Да нет, просто мне администрация Хабра на мой вопрос, «как публиковать формулы» ответила, что только используя изображение. А поскольку формул много, в целях экономии времени, я весь текст в картинки перевел.
Чтобы сложить или вычесть два числа надо выравнять их порядки. В случае нормализованных чисел всегда сдвигается вправо мантисса числа с меньшим порядком. Влево нормализованное число сдвигаться не может по определению.
Для чисел ненормализованных, чтобы обеспечить оптимальное сложение, надо, наоборот, в числе с большим порядком сдвигать мантиссу влево и одновременно уменьшать значение порядка до тех пор пока, либо порядки не выравняются, либо, пока в старшем разряде мантиссы ни появится единица. В последнем случае, если порядки слагаемых не сравнялись, надо сдвигать мантиссу числа с меньшим порядком вправо, увеличивая значение порядка этого числа, пока порядки слагаемых не сравняются. Пример. 0.001*2^(2)+0.01*2(-1). Порядок первого слагаемого больше порядка второго слагаемого. Будем сдвигать мантиссу первого слагаемого влево: 0.001*2^(2)=0.01*2^(1)=0.1*2^(0). Дальнейшее смещение мантиссы невозможно. Будем смещать мантиссу второго слагаемого вправо: 0.01*2(-1)=0.001*2(0). Порядки сравнялись, можно найти сумму: 0.1*2^(0)+0.001*2^(0)=0.101*2^(0). Мы здесь обошлись без нормализации, а результат автоматически получился записанным оптимальным образом, т.е. дробная мантисса в старшем разряде имеет единицу.

Согласен, нормализация дает положительный эффект при проведении математических операций. Но, видимо, до тех пор, пока речь не идет о малых числах. О таких числах, когда порядок числа достигает своего минимального значения и приходиться переходить к денормализованным числам. Если нормализацию заменить оптимизацией, т.е. числа представлять так, чтобы старший единичный разряд мантиссы числа всегда, когда это возможно, занимал крайнее левое положение, то тем самым мы получаем все преимущества нормализованных чисел. Но, в тех случаях, когда оптимизация приводит к антипереполнению, числа должны записываться без изменений. Признаком таких малых чисел является наличие нуля в старшем разряде мантиссы числа.
Чтобы огромное количество нулей не затрудняло понимания вопроса, давайте масштабируем Ваш пример:

умножаем 1 на 1. В нормализованном виде это 2^0 * 1, в двоичном представлении: порядок 0x3fff, мантисса: 0x80000000_00000000. При умножении 64-битных мантисс получается 128-битное произведение, из которого нужно выбрать 64-битный результат. Мы выбираем старшие 64 бита (с 64го по 127й) если 127й бит равен 1 (дополнительно увеличивая экспоненту результата на 1) либо старшие 64 бита (с 63го по 126й) в противном случае.
Т.е. 0x80000000_00000000 * 0x80000000_00000000 = 0x40000000_00000000_00000000_00000000, результат: биты с 63го по 126й, мантисса: (0x3fff — 0x3fff) + (0x3fff — 0x3fff) + 0x3fff = 0x3fff.


следующим образом.

Умножаем 1 на 1. В нормализованном виде это 2^0 * 1. В двоичном представлении: порядок 0x0, мантисса: 0x08. При умножении 4-битных мантисс получается 8-битное произведение, из которого нужно выбрать 4-битный результат. Мы выбираем старшие 4 бита (с 4 го по 7й) если 7й бит равен 1 (дополнительно увеличивая экспоненту результата на 1) либо старшие 4 бита (с 3го по 6й) в противном случае.
Т.е. 0x08 * 0x08 = 0x40, результат: биты с 3го по 6й, порядок равен 0.

Здесь я дословно привел Ваш пример в другом масштабе, только порядки представил без смещения. Мне кажется, что суть от этого не изменилась.

Рассмотрим теперь эту последовательность действий на шестнадцатеричных и двоичных числах:
0х08*0х08 = 0х40 = 1000*1000 = 0100 0000.

Далее дословно (с учетом масштабирования):
мы выбираем старшие 4 бита (с 4 го по 7й) если 7й бит равен 1 (дополнительно увеличивая экспоненту результата на 1) либо старшие 4 бита (с 3го по 6й) в противном случае.

У нас 7й бит равен 0, значит выбираем второй вариант.

Второй шаг равносилен сдвигу разрядов полученного числа влево на единицу. Число увеличилось в 2 раза, следовательно порядок должен быть уменьшен на 1. Будем иметь:
0100 0000 = 1000 0000*2^(-1). В старшем 7м разряде появилась единица. Следовательно, далее, по вашему алгоритму, преобразования должны завершиться. Надо выбрать 4 старших разряда и
порядок увеличить на 1. Получаем число, записанное в машинном слове, как 0х08 и порядок, равный нулю.

Рассмотрим теперь, как выглядят преобразования, когда числа не нормализуются. Поскольку мантисса машинного слова — дробная, число 1 будет представлено как 0.1*2^1. В области машинной мантиссы будет записано число 1000, а в области машинного порядка будет записано число 1. умножим это число само на себя и получим:
1000*1000 = 01000000. С учетом того, что мантисса у нас дробная, ее значение будет равно 0.01.
Порядок полученного числа будет равен 1+1=2. Сдвигаем полученное число влево до тех пор пока в старшем разряде области машинной мантиссы не появится 1. Всего нужно произвести 1 сдвиг. На такое же число уменьшаем порядок, который становится равным 2-1=1. В машинную область мантиссы записываем только 4 старших разряда. Больше не поместится. Таким образом, в результате, в машинном слове будет записано число 1000, а в области машинного порядка число 1. Что соответствует числу 0.1*2^1.
Является ли это нормализацией? Я бы назвал это оптимизацией. При больших числах нормализация и оптимизация алгоритмически совпадают. Но при маленьких числах нормализация дает совсем другой результат.

Речь об аргументах и их взаимной нормализации. Например вычтем (или прибавим, в данном случае не важно) из ненормализованной 1, представленной в двоичном виде как порядок: 0x403e, мантисса: 0x00000000_00000001 ненормализованную 1/4, представленную как порядок: 0x3ffd, мантисса: 0x80000000_00000000.
Для выполнения этого действия мантиссу 1 придётся сдвинуть налево, а мантиссу 1/4 — направо, так, чтобы обе единицы остались в пределах 64 бит, но старший бит 1 был бы левее старшего бита 1/4. Сдвигом только одной мантиссы этого добиться нельзя.


Вы правы, сдвигом мантиссы только одного числа этого не добиться.

Здесь надо подумать.
Извините, опять напутал с выделением цитат.
Т.е. умножая 1 на 1 в двоичном виде мы умножаем старшие разряды 0x8000 на 0x8000 и получаем 0x40000000. В итоговом результате надо проверить только старший бит, и если он нулевой — сдвинуть всё на один бит влево и увеличить порядок.


Поправьте меня, если я ошибаюсь. В Вашем примере 1 — это мантисса числа. В числе, возможно, присутствует характеристика 2^h_1. Т.е. первое число равно 1∙ 2^(h_1). Второе число равно 1∙ 2^(h_2). Умножаем первое на второе и получаем: 1∙ 2^(h_1)∙1∙ 2^(h_2) = 1∙ 2^(h_1+h_2). Мантисса здесь не изменилась. Изменился только порядок характеристики. Если порядок не вызвал переполнения, то он записывается в машинное слово без изменений.
Предположим теперь, что числа не нормализованы. По условию ненормализованных по стандарту чисел, мантисса машинного слова может быть только дробным числом. Тогда оба наших числа из Вашего примера оказываются за пределами разрядной сетки машинной мантиссы. Числа, которые выходят за область определения разрядной сетки машинной мантиссы должны быть приведены к необходимому виду, как при условии нормализации так и без нее. В таком виде они и должны храниться.В нашем случае числа должны быть приведены к виду, когда они меньше 0. Это похоже на нормализацию. Но условия нормализации другие. Где находится старший разряд в мантиссе слагаемого не имеет значения. Важно, чтобы полученный результат не вышел за пределы области машинной мантиссы. Если нет переполнения разрядной сетки машинной мантиссы, то результат будет верен и записывается в машинное слово в том виде, как получен при вычислении.

— сложение/вычитание: всегда сдвигается максимум один аргумент, всегда вправо.
В отсутствие нормализации может возникнуть ситуация, когда придётся сдвигать один аргумент влево, а другой вправо.

Я не могу придумать такой ситуации. При сложении двух чисел, всегда может возникнуть ситуация, когда появляется еще одна старшая единица. И если она не выходит за пределы разрядной сетки области машинной мантиссы, то результат должен быть записан в машинное слово без изменения. Если же есть переполнение, то конечно результат должен быть сдвинут на один разряд, а порядок увеличен тоже на 1 разряд.
Из этого не следует ненужность нормализации, поскольку она может быть полезна по другим соображениям.


Хотелось бы услышать эти соображения. В каких случаях нормализация полезна и в чем ее польза. Основная проблема, ради которой была предложена нормализация, это ликвидация неоднозначности представления экспоненциальных чисел. В статье показано, что неоднозначность представления чисел не является проблемой и потому нормализация не нужна.

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


Я не являюсь профессиональным программистом. Однако мне кажется, что быстродействие любого алгоритма зависит прежде всего от сложности этого алгоритма. А для того, чтобы сравнить, как быстро работает сопроцессор FPU, использующий числа с плавающей точкой с нормализацией и без нее, надо реализовать обработку чисел в самом сопроцессоре.
Говоря, что денормализованные числа, это необходимость, я имел ввиду, что необходимостью является решение проблемы работы с малыми числами. Одной из решения такой проблемы является просто отказаться от их использования. Но ведь, как я показал в статье, отказавшись от ненужной операции нормализации, мы бесплатно получаем возможность работы с малыми числами.
Здесь я согласен! Когда у тебя есть тяжелый микроскоп, зачем еще нужен молоток.
Поскольку 13.07.15 я был off-line и не мог вовремя реагировать. Хотелось бы ответить господину jcmvbkbc относительно проблемы нуля.
В нормализованных числах есть проблема получения нуля в явном виде. Отсюда возникает проблема сравнения на равенство двух чисел.
Для нормализованных чисел два числа считаются равными, если они отличаются друг от друга на «бесконечно» малую величину. Но, согласитесь, что с математической точки зрения, нуль и число, близкое к нулю, вещи разные.
Если, как предложено в статье, отказаться от нормализации чисел, то эта проблема с нулем решается, т.к. нуль представлен в явном виде… Одновременно появляется возможность оперировать с таким понятием, как бесконечно малое число.
Учитывать значения мантисс при любой арифметической операции конечно необходимо, но зачем для этого нормализовывать числа? Вы же сами говорите, что учет значений мантисс, чтобы не было переполнения/потери точности, это и есть фактически нормализация. Тогда зачем нормализовывать уже нормализованное число?
При работе с большими числами нормализация происходит автоматически, при их правильной математической обработке. Проблемы возникают с малыми числами. Когда малые числа нормализуют, тогда и вылезают все неприятности. И нулем приходится жертвовать и вводить искусственно класс денормализованных чисел со всеми вытекающими…
Извините, я тут нечаянно не ту клавишу нажал. Выше была цитата:).Простите чайника.

Мой ответ: Не зависимо, как реализуется алгоритм, программно или в железе, сложный алгоритм реализуется сложно.
Денормализованные числа — это конечно необходимость. Именно поэтому за них так много «платят». А если убрать нормализацию, как показано в статье, то они ничем не отличаются от прочих, «нормальных» чисел.
Это вы говорите о программной реализации операций с плавающей точкой? А если реализация «железная»?
Нормализация придумана прежде всего для решения проблемы неоднозначности представления чисел в машинном слове. Экономия же одного бита, это побочный положительный эффект, ради которого вряд-ли стали бы городить огород.
Слишком дорогой ценой дается такая экономия. Во-первых, невозможность получения в явном виде нуля и, во-вторых, необходимость введения денормализованных чисел. На выходе — огромный кусок бесполезной работы.
12 ...
16

Information

Rating
Does not participate
Location
Минск, Минская обл., Беларусь
Registered
Activity