C - добавление двух обычных чисел с плавающей запятой одинарной точности, не может получить результат до бесконечности

Я играю с арифметикой с плавающей запятой, и я столкнулся с чем-то, что нуждается в объяснении.

При установке режима округления на «к нулю», иначе:

fesetround(FE_TOWARDZERO);

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

Однако из IEEE 745 известно, что переполнение до бесконечности может быть результатом сложения конечных чисел.

Например:

#include <fenv.h>
#include <stdio.h>

float hex2float (int hex_num) {
  return *(float*)&hex_num;
}

void main() {
  int a_int = 0x7f7fffff; // Maximum finite single precision number, about 3.4E38
  int b_int = 0x7f7fffff;
  float a = hex2float(a_int);
  float b = hex2float(b_int);
  float res_add;

  fesetround(FE_TOWARDZERO);  // need to include fenv.h for that
  printf("Calculating... %+e + %+e\n",a,b);
  res_add = a + b;
  printf("Res = %+e\n",res_add);
}

Однако, если я изменю режим округления на что-то другое, я могу получить +INF в качестве ответа.

Кто-нибудь может это объяснить?


person Shay Golan    schedule 25.05.2016    source источник
comment
Я понятия не имею, что делает hex2float, так как вы даже не упомянули библиотеку, которую используете. Но я почти уверен, что это не займет ints..   -  person Eugene Sh.    schedule 25.05.2016
comment
@EugeneSh.: определение hex2float находится в опубликованном коде.   -  person Dolda2000    schedule 25.05.2016
comment
Ой. пропустил его. Строгое нарушение алиасинга.   -  person Eugene Sh.    schedule 25.05.2016
comment
@EugeneSh.: Конечно, но четко определено во всей реальной практике.   -  person Dolda2000    schedule 25.05.2016
comment
Во всяком случае, плохое именование функций. Это не имеет ничего общего с hex.   -  person Eugene Sh.    schedule 25.05.2016
comment
Определенно должен быть назван int2float(), так как не существует типа данных hex.   -  person alk    schedule 25.05.2016
comment
@EugeneSh.: Я согласен, но это имеет мало общего с реальным вопросом. :)   -  person Dolda2000    schedule 25.05.2016
comment
И никак, это УБ. (stackoverflow.com/q/98650/694576)   -  person alk    schedule 25.05.2016
comment
@ Dolda2000 Да, просто комментирую :) Пришлось разобраться, прежде чем смотреть на настоящую проблему ..   -  person Eugene Sh.    schedule 25.05.2016
comment
@alk хорошо, давайте предположим, что это не на мгновение ..   -  person Eugene Sh.    schedule 25.05.2016
comment
@alk: Если вы имеете в виду псевдоним указателя, то, возможно, это так, но это не причина поведения, о котором спрашивают.   -  person Dolda2000    schedule 25.05.2016
comment
Так каков фактический результат?   -  person Eugene Sh.    schedule 25.05.2016
comment
@EugeneSh.: После проверки результат MAXFLOAT, как и a и b.   -  person Dolda2000    schedule 25.05.2016
comment
Разве это не то, что вы ожидаете от округления до нуля? Вещественный результат сложения больше любого конечного числа с плавающей запятой, но округляется до наибольшей величины с плавающей запятой, которая не дальше нуля, MAXFLOAT.   -  person Patricia Shanahan    schedule 25.05.2016
comment
Я думаю, что это довольно исчерпывающе...   -  person Eugene Sh.    schedule 25.05.2016
comment
А что касается лимитных констант, вам следует использовать предопределенные макросы вместо того, чтобы создавать загадочную магию указателей: en. cppreference.com/w/c/types/limits   -  person Eugene Sh.    schedule 25.05.2016
comment
@PatriciaShanahan: Следуя этой логике, вы также можете утверждать, что округление FE_TONEAREST должно также иметь MAXFLOAT + MAXFLOAT == MAXFLOAT, поскольку любой конечный результат будет математически ближе к MAXFLOAT, чем к бесконечности. ;)   -  person Dolda2000    schedule 25.05.2016
comment
Спасибо вам всем. Кстати, я использую имя hex2float, а не int2float, потому что преобразование между целым числом и числом с плавающей запятой не выполняется. то есть: от 7 до 7,0. Это делается из двоичного (или шестнадцатеричного) представления типа с плавающей запятой в тип с плавающей запятой.   -  person Shay Golan    schedule 25.05.2016
comment
@ShayGolan Двоичные/шестнадцатеричные/десятичные/восьмеричные или любые другие представления абсолютно эквивалентны. Почему вы различаете десятичное число, когда говорите двоичное (или шестнадцатеричное)?   -  person Eugene Sh.    schedule 25.05.2016
comment
Да, вы правы. Но я предпочел назвать функцию именно так, чтобы избежать путаницы с преобразованием между целым числом и числом с плавающей запятой.   -  person Shay Golan    schedule 25.05.2016
comment
Использование float a = FLT_MAX; позволило бы избежать отвлекающего обсуждения hex2float().   -  person chux - Reinstate Monica    schedule 25.05.2016


Ответы (1)


Объяснение наблюдаемого поведения заключается в том, что оно предписано стандартом IEEE 754-2008 для операций с плавающей запятой:

7.4 Переполнение

Исключение переполнения должно быть сообщено тогда и только тогда, когда наибольшее конечное число целевого формата превышено по величине на то, что было бы округленным результатом с плавающей запятой (см. 4), если бы диапазон экспоненты не был ограничен. Результат по умолчанию должен определяться атрибутом направления округления и знаком промежуточного результата следующим образом:

[...]

б) roundTowardZero сводит все переполнения к наибольшему конечному числу формата со знаком промежуточного результата.

Таким образом, для используемого здесь режима округления (усечение или округление до нуля) результатом в случае переполнения является наибольшее конечное число, не бесконечность.

person njuffa    schedule 25.05.2016