3

На gcc 4.7.3, мой fegetround() функция возвращает FE_TONEAREST. Согласно c++ reference, это означает округление от нуля. По сути, это означает сохранение последнего бит, который был сдвинут при настройке точности мантиссы после умножения (так как он будет в два раза длиннее, чем должен). После этого сохраненный бит добавляется к окончательному результату мантиссы.Неверное округление с плавающей точкой

Например, с плавающей запятой умножения дает следующие результаты:

0x38b7aad5 * 0x38b7aad5 = 0x3203c5af 

мантисса после умножения

1011 0111 1010 1010 1101 0101 
x 1011 0111 1010 1010 1101 0101 
------------------------------- 
1[000 0011 1100 0101 1010 1110] [1]000 0101 1001 0101 0011 1001 

[23'b] набора имеет значащие цифры, в то время как [1'b] набор содержит последний бит смещен. Обратите внимание, что мантисса для результата

[000 0011 1100 0101 1010 1111] 

Последний бит переключается на 1 потому что [1'b1] набор был добавлен к сплайсингу мантиссы (The [23'b] комплект) в связи с режимом округления.

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

0x20922800 * 0x20922800 = 0x1a6e34c (check this on your machine) 

    1010 0110 1110 0011 0100 1101 
x 1010 0110 1110 0011 0100 1101 
------------------------------- 
01[01 0011 0111 0001 1010 0110 0][1]00 0000 0000 0000 0000 0000 

Final Mantissas:  
Their Result:  01 0011 0111 0001 1010 0110 0 
Correct Result(?): 01 0011 0111 0001 1010 0110 1 

Я весь день хруст бинарный, так что, возможно, мне не хватает чего-то простого здесь. Какой ответ правильный с заданным режимом округления?

+2

«возвращает FE_TONEAREST. Согласно ссылке C++, это означает округление от нуля "-> Вы уверены? Посмотрите еще раз на имя. –

+11

Я думаю, что всякий раз, когда возникает вопрос «Моя ошибка или Intel», вы можете дать ответ, не прочитав вопрос, и в 99% случаев вы будете правы. –

+3

Если у вас нет Pentium первого поколения. – dan04

ответ

6

При округлении до ближайшего, IEEE указывает, что связи округлены до четного. 0 четный, 1 нечетный, поэтому Intel верен.

+0

Не означает ли это, что все неточные вычисления заканчиваются «0» в мантиссе? Почему не первый? – Suedocode

+5

@Aggieboy: Это только раунды от 1/2 до четного. Если вы даже йота выше 1/2, она будет округлена, как в вашем первом примере. Ваш второй пример округлялся _exactly_ 1/2. –

+0

Ага, это было объяснение, которое я искал! Я неправильно понял, что означал этот режим округления. – Suedocode

2

Первый округление до ближайшего не хватает одна деталь здесь. Это округление до ближайшего (даже).

IEEE 754 стандарт (раздел 4.3.1) цитата:

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

В первом примере вы вычислить квадрат (8.75794e-5) который (если представлен как 32-битный float) имеет следующий шестнадцатеричный шаблон: 0x38b7aad5.

Все 24 значащих бита (8.75794e-5) являются:

0xb7aad5 = 1.0110111_10101010_11010101 

Теперь после возведения в квадрат, что вы получите:

1.0000011_11000101_10101110_10000101_10010101_00111001 

Следует отметить, что в 99% случаев ваши расчеты будут выполняться на FPU (возможно, x87), который работает с 80-битным форматом с плавающей запятой.

Intel® 64 и IA-32 Архитектуры Software Developer Руководство

(программирование с x87 FPU):

Когда с плавающей точкой, целое число, или упакованное BCD целое значения загружаются из памяти в любой регистр данных FPU x87, значения автоматически преобразуются в формат с плавающей запятой с двойной точностью (если они еще не в этом формате).

Теперь вы хотите сохранить свой результат в 32 битной плавающей точкой:

1.[0000011_11000101_10101110]10000101_10010101_00111001 

и здесь, где режимы округления дело. IEEE 754 определяет 4 из них, но давайте сосредоточимся на стандартном (округление до ближайшего (четного)), как мы обсуждаем здесь.

Теперь, когда ваш FPU имеет результат (в целом - мы имеем 64 значащих бита в 80-битном формате), он должен выполнить округление, чтобы соответствовать числу в пределах 32 бит (24 знака и бит). Все 23 бита, которые должны быть явно сохранены, помещаются в скобки выше.

Теперь округление до ближайшего не имеет ничего общего с даже словом в данном конкретном случае поскольку биты в правой части кронштейна является не на полпути между:

1.[0000011_11000101_10101111] 
and 
1.[0000011_11000101_10101110] 

, но они ближе к

1.[0000011_11000101_10101111] 

Вот почему значение вашего результата - 0x3203C5AF.

Теперь проблематичный результат возведения в квадрат 2.4759832E-19 0x20922800.

24 значащих бита 2.4759832E-19 являются:

0x922800 = 1.0010010_00101000_0000_0000 

и квадрат:

1.[0100110_11100011_01001100]10000000_00000000_0000000 

А вот где даже часть действительно имеет значение. Теперь ваше значение находится ровно на полпути между:

1.[0100110_11100011_01001101] 
and 
1.[0100110_11100011_01001100] 

Вышеуказанные значения, как говорят, привязывают ваше значение. Из них вам теперь нужно выбрать один (последний с lsb = 0).

Теперь вы знаете, почему 24бит ваш результата является 0xA6E34C (ближайших даже) и не 0xA6E34D (ближайшим, но нечетный)

Смежные вопросы