минимальное двойное значение в C / C ++

92

Существует ли стандартный и / или переносимый способ представления наименьшего отрицательного значения (например, использование отрицательной бесконечности) в программе на C (++)?

DBL_MIN в float.h - это наименьшее положительное число.

Будет
источник
4
Я выберу -DBL_MAX, но я уверен, что есть какая-то техническая причина, почему это не так :-)
4
@Neil, нет, это не похоже на 2 целых числа с дополнением
fortran
Я еще не видел ничего в стандарте, чтобы сказать, что диапазон типов с плавающей запятой должен быть симметричным относительно нуля. Но константы в limits.h и <limits> предполагают, что стандарты C и C ++ отчасти ожидают, что они будут такими.
Стив Джессоп,
4
Фактически DBL_MIN в float.h - это наименьшее положительное нормализованное число. Есть цифры, которые еще меньше.
fdermishin
1
@fortran: IEEE 754 FP использует знаковый бит, и, безусловно, большая часть оборудования FP в наши дни - это IEEE 754. Но C и C ++ поддерживают оборудование FP, отличное от IEEE 754, поэтому остается открытым вопрос о том, дает ли язык гарантию, что -DBL_MAX должен быть равен минимальному представимому значению.
j_random_hacker

Ответы:

135

-DBL_MAX в ANSI C , который определен в float.h.

DFA
источник
это кажется самым стандартным и портативным
Will
Вот объяснение моего -1: кто или что говорит, что -DBL_MAX гарантировано языком C или C ++ представимым, не говоря уже о минимальном представимом значении? Тот факт, что большая часть оборудования FP соответствует стандарту IEEE 754 и использует это представление, не означает, что -DBL_MAX гарантированно работает на любой стандартной платформе C.
j_random_hacker
@j_random_hacker: см. ответ Фортрана «ниже».
JohnTortugo
3
@j_random_hacker Это очень хороший момент, но стандарт C требует, -DBL_MAXчтобы он был точно представлен, поэтому, если оборудование FP не способно на это, реализация просто должна обойти это. См. Модель с плавающей запятой в 5.2.4.2.2 Характеристики типов с плавающей запятой <float.h> p2 в C99 (с тех пор, возможно, были перемещены в другое место).
2
@j_random_hacker Да, но p2 указывает, что e_min и e_max не зависят от знакового бита, поэтому DBL_MAXточно (1 - b ^ −p) b ^ e_max, что точно представимо, наиболее отрицательное конечное значение точно - (1 - b ^ −p) b ^ e_max, и поскольку это точно -DBL_MAX, отрицание также DBL_MAXне может привести к ошибкам округления.
70

Числа с плавающей запятой (IEEE 754) симметричны, поэтому, если вы можете представить наибольшее значение ( DBL_MAXилиnumeric_limits<double>::max() ), просто добавьте знак минус.

А потом крутой способ:

double f;
(*((long long*)&f))= ~(1LL<<52);
Фортран
источник
6
+1 За указание на симметрию чисел с плавающей запятой :)
Эндрю Хэйр
4
Как насчет реализаций C / C ++, которые не используют числа с плавающей запятой IEEE 754?
Стив Джессоп,
1
В руководстве gcc для -ffast-math говорится: «Устанавливает -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans и -fcx-limited- диапазон Эта опция не включается ни одной опцией -O, так как это может привести к некорректному выводу программ, которые зависят от точной реализации правил / спецификаций IEEE или ISO для математических функций. Однако он может дать более быстрый код для программ, которые не требуют гарантий этих спецификаций ». Быстрая математика - это обычная настройка, и Intel ICC, например, использует ее по умолчанию. В общем, не уверен, что это значит для меня :-)
Will
4
Это означает, что реализации не используют арифметику IEEE 754, но, честно говоря, эти варианты все еще используют представление IEEE. Вы можете найти некоторые библиотеки эмуляции, использующие представление, отличное от IEEE, поскольку не все процессоры имеют собственный формат с плавающей запятой (хотя они могут публиковать C ABI, который включает формат, соответствующий библиотекам эмуляции, предоставленным производителем). Следовательно, не все компиляторы могут использовать один. Просто зависит от того, что вы имеете в виду, когда спрашиваете о «стандартном и / или портативном», есть портативные в принципе и портативные на практике.
Стив Джессоп,
3
То, что вы говорите, верно для IEEE 754, но стандарт не требует использования этой кодировки (как указывает @SteveJessop, переносимый на практике не то же самое, что переносимый в принципе).
Christophe
44

В C используйте

#include <float.h>

const double lowest_double = -DBL_MAX;

В C ++ до 11 используйте

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

В C ++ 11 и новее используйте

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();
rubenvb
источник
Разве эта min()функция не была доступна до C ++ 11? Или это другое значение, чем -max()? en.cppreference.com/w/cpp/types/numeric_limits
Алексис
5
@Alexis: если вы посмотрите на три нижние строки в таблице на странице, которую вы связали, вы увидите, что minдает вам наименьшее положительное значение по величине и lowestнаибольшее отрицательное значение по величине. Да это ужасно. Добро пожаловать в блестящий мир стандартной библиотеки C ++ :-P.
rubenvb
для C он определен в float.h. limits.hдля целых чисел
Ciprian Tomoiagă
33

Попробуй это:

-1 * numeric_limits<double>::max()

Справка: numeric_limits

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

Эндрю Хэйр
источник
1
Почему не просто так -numeric_limits<double>::max()?
k06a
4
@ k06a, имеющая отрицание, представленное одним символом в таком длинном выражении, где в строке даже написано "max", рано или поздно наверняка кого-нибудь найдет. Либо он хранится в описательной переменной, либо используется, -1 * ...чтобы сделать его немного понятнее.
Филип Хаглунд
20

Вы ищете актуальную бесконечность или минимальное конечное значение? Если первое, используйте

-numeric_limits<double>::infinity()

который работает только если

numeric_limits<double>::has_infinity

В противном случае вы должны использовать

numeric_limits<double>::lowest()

который был введен в C ++ 11.

Если lowest()недоступен, вы можете вернуться к

-numeric_limits<double>::max()

которые могут отличаться от них lowest()в принципе, но обычно не работают.

Кристоф
источник
+1 за разницу между конечным и бесконечным значением! Но стандарт не гарантирует симметричное кодирование с плавающей запятой. Таким образом, -numeric_limits<double>::max()даже если он работает на практике, он не является полностью переносимым в теории.
Christophe
@Christophe: [x] исправлено
Christoph
10

По-настоящему портативное решение на C ++

Начиная с C ++ 11 вы можете использовать numeric_limits<double>::lowest(). Согласно стандарту он возвращает именно то, что вы ищете:

Конечное значение x такое, что не существует другого конечного значения y, где y < x.
Имеет значение для всех специализаций, в которых is_bounded != false.

Онлайн-демонстрация


Здесь много непереносимых ответов на C ++!

Есть много ответов -std::numeric_limits<double>::max().

К счастью, в большинстве случаев они подойдут. В схемах кодирования с плавающей запятой число разлагается на мантиссу и показатель степени, и большинство из них (например, популярный IEEE-754 ) используют отдельный знаковый бит, который не принадлежит мантиссе. Это позволяет преобразовать самый большой положительный результат в самый маленький отрицательный, просто перевернув знак:

введите описание изображения здесь

Почему они не портативны?

Стандарт не устанавливает никаких стандартов с плавающей запятой.

Я согласен с тем, что мой аргумент является немного теоретическим, но предположим, что какой-нибудь эксцентричный производитель компиляторов будет использовать революционную схему кодирования с мантиссой, закодированной в некоторых вариантах дополнения до двух. . Кодирование с дополнением до двух не является симметричным. например, для 8-битного символа со знаком максимальное положительное значение - 127, а минимальное отрицательное - -128. Таким образом, мы могли представить себе некоторую кодировку с плавающей запятой, показывающую подобное асимметричное поведение.

Я не знаю ни одной такой схемы кодирования, но дело в том, что что стандарт не гарантирует, что смена знака даст желаемый результат . Так что этот популярный ответ (извините, ребята!) Нельзя рассматривать как полностью портативное стандартное решение! / * по крайней мере, если вы не утверждали, что numeric_limits<double>::is_iec559это правда * /

Кристоф
источник
1

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

#define Infinity  ((double)(42 / 0.0))

согласно определению IEEE? Вы, конечно, можете отрицать это.

Норберт
источник
Хорошая идея ! И это работает . Но только еслиnumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe
1

Существует ли стандартный и / или переносимый способ представления наименьшего отрицательного значения (например, использование отрицательной бесконечности) в программе на C (++)?

C. подход.

Многие реализации поддерживают +/- бесконечности, поэтому самое отрицательное doubleзначение -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

Есть стандартный и / или портативный способ ....?

Теперь нам нужно рассмотреть и другие случаи:

  • Без бесконечностей

Просто -DBL_MAX.

  • Только беззнаковая бесконечность.

Я ожидал, что в этом случае OP предпочтет -DBL_MAX.

  • Ненормальные значения по величине больше, чем DBL_MAX.

Это необычный случай, вероятно, не имеющий отношения к OP. Когда doubleкодируется как пара с плавающей запятой для достижения желаемого диапазона / прецессии (см. Double-double ), существует максимальное нормальное значение double и, возможно, большее ненормальное . Я видел дебаты, DBL_MAXследует ли ссылаться на величайший нормальный , величайшему из обоих.

К счастью, этот парный подход обычно включает -infinity, поэтому остается наиболее отрицательное значение -INFINITY.


Для большей переносимости код может пойти по пути

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;
chux - восстановить Монику
источник
-1

Если у вас не включены исключения с плавающей запятой (чего не следует имхо), вы можете просто сказать:

double neg_inf = -1/0.0;

Это дает отрицательную бесконечность. Если вам нужен float, вы можете преобразовать результат

float neg_inf = (float)-1/0.0;

или используйте арифметику одинарной точности

float neg_inf = -1.0f/0.0f;

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

cmaster - восстановить монику
источник
Зачем вам делать это вместо того, чтобы просто писать?-INFINITY
MM
Кроме того, бесконечность может существовать или не существовать, и если она существует, то положительное и отрицательное могут быть неразличимы (в Стандарте C).
MM
Во многих компиляторах и / или архитектурах ваш код C / C ++ будет замедлять, многие из вас распространяют бесконечность и значения NaN.
markgalassi
@markgalassi Присмотритесь внимательнее: вы заметите, что neg_infон инициализируется постоянным значением . Компилятор позаботится о вычислении infзначения. И когда вы используете его как нулевое значение для вычисления максимума, первая итерация обычно перезаписывает его с большим значением. Т.е. производительность вряд ли проблема. И ОП конкретно спрашивает о «например, использовать отрицательную бесконечность», и -infэто действительно единственный правильный ответ на этот вопрос. Вы проголосовали против правильного и полезного ответа.
cmaster - восстановить Монику