Существует ли стандартный и / или переносимый способ представления наименьшего отрицательного значения (например, использование отрицательной бесконечности) в программе на C (++)?
DBL_MIN в float.h - это наименьшее положительное число.
Я выберу -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 должен быть равен минимальному представимому значению.
Вот объяснение моего -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() ), просто добавьте знак минус.
+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, переносимый на практике не то же самое, что переносимый в принципе).
@Alexis: если вы посмотрите на три нижние строки в таблице на странице, которую вы связали, вы увидите, что minдает вам наименьшее положительное значение по величине и lowestнаибольшее отрицательное значение по величине. Да это ужасно. Добро пожаловать в блестящий мир стандартной библиотеки C ++ :-P.
rubenvb
для C он определен в float.h. limits.hдля целых чисел
Этот класс специализирован для каждого из основных типов, его члены возвращают или устанавливают различные значения, которые определяют свойства, которые тип имеет на конкретной платформе, на которой он компилируется.
Почему не просто так -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.
Есть много ответов -std::numeric_limits<double>::max().
К счастью, в большинстве случаев они подойдут. В схемах кодирования с плавающей запятой число разлагается на мантиссу и показатель степени, и большинство из них (например, популярный IEEE-754 ) используют отдельный знаковый бит, который не принадлежит мантиссе. Это позволяет преобразовать самый большой положительный результат в самый маленький отрицательный, просто перевернув знак:
Почему они не портативны?
Стандарт не устанавливает никаких стандартов с плавающей запятой.
Я согласен с тем, что мой аргумент является немного теоретическим, но предположим, что какой-нибудь эксцентричный производитель компиляторов будет использовать революционную схему кодирования с мантиссой, закодированной в некоторых вариантах дополнения до двух. . Кодирование с дополнением до двух не является симметричным. например, для 8-битного символа со знаком максимальное положительное значение - 127, а минимальное отрицательное - -128. Таким образом, мы могли представить себе некоторую кодировку с плавающей запятой, показывающую подобное асимметричное поведение.
Я не знаю ни одной такой схемы кодирования, но дело в том, что что стандарт не гарантирует, что смена знака даст желаемый результат . Так что этот популярный ответ (извините, ребята!) Нельзя рассматривать как полностью портативное стандартное решение! / * по крайней мере, если вы не утверждали, что numeric_limits<double>::is_iec559это правда * /
Хорошая идея ! И это работает . Но только если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);
// Pragmaticdouble most_negative3 = strtod("-1.0e999999999", (char **) NULL);
// Somewhat time-consumingdouble most_negative4 = pow(-DBL_MAX, 0xFFFF/* odd value */);
// My suggestiondouble most_negative5 = (-DBL_MAX)*DBL_MAX;
Если у вас не включены исключения с плавающей запятой (чего не следует имхо), вы можете просто сказать:
double neg_inf = -1/0.0;
Это дает отрицательную бесконечность. Если вам нужен float, вы можете преобразовать результат
float neg_inf = (float)-1/0.0;
или используйте арифметику одинарной точности
float neg_inf = -1.0f/0.0f;
Результат всегда один и тот же, существует ровно одно представление отрицательной бесконечности как с одинарной, так и с двойной точностью, и они преобразуются друг в друга, как и следовало ожидать.
Зачем вам делать это вместо того, чтобы просто писать?-INFINITY
MM
Кроме того, бесконечность может существовать или не существовать, и если она существует, то положительное и отрицательное могут быть неразличимы (в Стандарте C).
MM
Во многих компиляторах и / или архитектурах ваш код C / C ++ будет замедлять, многие из вас распространяют бесконечность и значения NaN.
markgalassi
@markgalassi Присмотритесь внимательнее: вы заметите, что neg_infон инициализируется постоянным значением . Компилятор позаботится о вычислении infзначения. И когда вы используете его как нулевое значение для вычисления максимума, первая итерация обычно перезаписывает его с большим значением. Т.е. производительность вряд ли проблема. И ОП конкретно спрашивает о «например, использовать отрицательную бесконечность», и -infэто действительно единственный правильный ответ на этот вопрос. Вы проголосовали против правильного и полезного ответа.
Ответы:
-DBL_MAX
в ANSI C , который определен в float.h.источник
-DBL_MAX
чтобы он был точно представлен, поэтому, если оборудование FP не способно на это, реализация просто должна обойти это. См. Модель с плавающей запятой в 5.2.4.2.2 Характеристики типов с плавающей запятой <float.h> p2 в C99 (с тех пор, возможно, были перемещены в другое место).DBL_MAX
точно (1 - b ^ −p) b ^ e_max, что точно представимо, наиболее отрицательное конечное значение точно - (1 - b ^ −p) b ^ e_max, и поскольку это точно-DBL_MAX
, отрицание такжеDBL_MAX
не может привести к ошибкам округления.Числа с плавающей запятой (IEEE 754) симметричны, поэтому, если вы можете представить наибольшее значение (
DBL_MAX
илиnumeric_limits<double>::max()
), просто добавьте знак минус.А потом крутой способ:
double f; (*((long long*)&f))= ~(1LL<<52);
источник
В 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();
источник
min()
функция не была доступна до C ++ 11? Или это другое значение, чем-max()
? en.cppreference.com/w/cpp/types/numeric_limitsmin
дает вам наименьшее положительное значение по величине иlowest
наибольшее отрицательное значение по величине. Да это ужасно. Добро пожаловать в блестящий мир стандартной библиотеки C ++:-P
.float.h
.limits.h
для целых чиселПопробуй это:
-1 * numeric_limits<double>::max()
Справка:
numeric_limits
источник
-numeric_limits<double>::max()
?-1 * ...
чтобы сделать его немного понятнее.Вы ищете актуальную бесконечность или минимальное конечное значение? Если первое, используйте
-numeric_limits<double>::infinity()
который работает только если
numeric_limits<double>::has_infinity
В противном случае вы должны использовать
numeric_limits<double>::lowest()
который был введен в C ++ 11.
Если
lowest()
недоступен, вы можете вернуться к-numeric_limits<double>::max()
которые могут отличаться от них
lowest()
в принципе, но обычно не работают.источник
-numeric_limits<double>::max()
даже если он работает на практике, он не является полностью переносимым в теории.По-настоящему портативное решение на C ++
Начиная с C ++ 11 вы можете использовать
numeric_limits<double>::lowest()
. Согласно стандарту он возвращает именно то, что вы ищете:Онлайн-демонстрация
Здесь много непереносимых ответов на C ++!
Есть много ответов
-std::numeric_limits<double>::max()
.К счастью, в большинстве случаев они подойдут. В схемах кодирования с плавающей запятой число разлагается на мантиссу и показатель степени, и большинство из них (например, популярный IEEE-754 ) используют отдельный знаковый бит, который не принадлежит мантиссе. Это позволяет преобразовать самый большой положительный результат в самый маленький отрицательный, просто перевернув знак:
Почему они не портативны?
Стандарт не устанавливает никаких стандартов с плавающей запятой.
Я согласен с тем, что мой аргумент является немного теоретическим, но предположим, что какой-нибудь эксцентричный производитель компиляторов будет использовать революционную схему кодирования с мантиссой, закодированной в некоторых вариантах дополнения до двух. . Кодирование с дополнением до двух не является симметричным. например, для 8-битного символа со знаком максимальное положительное значение - 127, а минимальное отрицательное - -128. Таким образом, мы могли представить себе некоторую кодировку с плавающей запятой, показывающую подобное асимметричное поведение.
Я не знаю ни одной такой схемы кодирования, но дело в том, что что стандарт не гарантирует, что смена знака даст желаемый результат . Так что этот популярный ответ (извините, ребята!) Нельзя рассматривать как полностью портативное стандартное решение! / * по крайней мере, если вы не утверждали, что
numeric_limits<double>::is_iec559
это правда * /источник
- std::numeric_limits<double>::max()
должно работать нормально
Числовые ограничения
источник
Исходный вопрос касается бесконечности. Итак, почему бы не использовать
#define Infinity ((double)(42 / 0.0))
согласно определению IEEE? Вы, конечно, можете отрицать это.
источник
numeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
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;
источник
Если у вас не включены исключения с плавающей запятой (чего не следует имхо), вы можете просто сказать:
double neg_inf = -1/0.0;
Это дает отрицательную бесконечность. Если вам нужен float, вы можете преобразовать результат
float neg_inf = (float)-1/0.0;
или используйте арифметику одинарной точности
float neg_inf = -1.0f/0.0f;
Результат всегда один и тот же, существует ровно одно представление отрицательной бесконечности как с одинарной, так и с двойной точностью, и они преобразуются друг в друга, как и следовало ожидать.
источник
-INFINITY
neg_inf
он инициализируется постоянным значением . Компилятор позаботится о вычисленииinf
значения. И когда вы используете его как нулевое значение для вычисления максимума, первая итерация обычно перезаписывает его с большим значением. Т.е. производительность вряд ли проблема. И ОП конкретно спрашивает о «например, использовать отрицательную бесконечность», и-inf
это действительно единственный правильный ответ на этот вопрос. Вы проголосовали против правильного и полезного ответа.