мінімальне подвійне значення в C / C ++


92

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

DBL_MIN у float.h - це найменше додатне число.


4
Я пойду на -DBL_MAX, але я впевнений, що існує якась технічна причина, чому це не так :-)

4
@Neil, ні, немає, це не як 2 цілі числа доповнення
fortran

Я ще нічого не бачив у стандарті, щоб сказати, що діапазон типів з плаваючою комою повинен бути симетричним навколо нуля. Але константи в limit.h та <limits> припускають, що як стандарт C, так і C ++ як би очікують, що вони будуть.
Steve Jessop

4
Насправді DBL_MIN у float.h - це найменше додатне нормоване число. Є цифри, які навіть менші.
fdermishin

1
@fortran: IEEE 754 FP використовує знаковий біт, і, звичайно, більшість апаратних засобів FP сьогодні є IEEE 754. Але C і C ++ підтримують апаратне забезпечення, що не відноситься до IEEE 754 FP, тому відкрито питання про те, чи дає мова гарантію, що -DBL_MAX має дорівнювати мінімальному представленому значенню.
j_random_hacker

Відповіді:


134

-DBL_MAX в ANSI C , що визначено в float.h.


це здається найбільш стандартним і портативним
Уілл

Ось пояснення мого -1: хто чи що говорить, що -DBL_MAX гарантується мовою C або C ++ бути репрезентабельним, не кажучи вже про мінімальне репрезентабельне значення? Той факт, що більшість апаратних засобів FP відповідає стандарту IEEE 754, і воно використовує це подання, не означає, що -DBL_MAX гарантовано працює на будь-якій стандартній платформі C-платформи.
j_random_hacker

@j_random_hacker: див. відповідь fortran "нижче".
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?
Steve Jessop

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, наприклад, за замовчуванням. Загалом, не впевнений, що це означає для мене :-)
Буде

4
Це означає, що реалізації не використовують арифметику IEEE 754, але, чесно кажучи, ці варіанти все ще використовують представлення IEEE. Ви можете знайти деякі бібліотеки емуляції, що використовують представлення не IEEE, оскільки не всі процесори мають власний плаваючий формат (хоча вони можуть опублікувати C ABI, який включає формат, відповідний бібліотекам емуляції, що постачаються виробником). Отже, не всі компілятори можуть використовувати один. Просто залежить від того, що ви маєте на увазі, коли просите "стандартний та / або портативний", портативний є в принципі і портативний на практиці.
Steve Jessop

3
Те, що ви говорите, відповідає дійсності IEEE 754, але стандарт не вимагає використання цього кодування (як зазначає @SteveJessop, портативний на практиці не те саме, що портативний в принципі).
Крістоф

44

У C, використовуйте

#include <float.h>

const double lowest_double = -DBL_MAX;

У C ++ pre-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_limits
Alexis Wilke

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] виправлено
Крістоф

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
Крістоф

1

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

С підхід.

Багато реалізацій підтримують +/- нескінченності, тому найбільш негативним doubleє значення -INFINITY.

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

Чи існує стандартний та / або портативний спосіб ....?

Тепер нам потрібно також розглянути інші випадки:

  • Немає нескінченностей

Просто -DBL_MAX.

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

Я б очікував, що в цьому випадку OP воліє -DBL_MAX.

  • Денормальні значення більші за величиною, ніж DBL_MAX.

Це незвичний випадок, який, ймовірно, не стосується ОП. Коли doubleкодується як пара плаваючих точок для досягнення бажаного діапазону / прецесії, (див. Подвійний-подвійний ) існує максимальна нормальна double і, можливо, більша нормальна . Я бачив суперечки, чи DBL_MAXслід посилатися на найбільше нормальне , з найбільшого з обох.

На щастя, цей парний підхід зазвичай містить -нескінченність, тому найбільш негативне значення залишається -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;

-1

Якщо у вас не ввімкнено винятки з плаваючою системою (чого не слід робити), ви можете просто сказати:

double neg_inf = -1/0.0;

Це дає негативну нескінченність. Якщо вам потрібна поплавка, ви можете або привести результат

float neg_inf = (float)-1/0.0;

або використовувати одиничну точну арифметику

float neg_inf = -1.0f/0.0f;

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


Чому ви робите це замість того, щоб просто писати-INFINITY
MM

Крім того, нескінченність може існувати, а може і не існувати, і якщо вона існує, то позитивні та негативні можуть не відрізнятися (у Стандарті С).
MM

У багатьох компіляторах та / або архітектурах ваш код C / C ++ сповільнює багато з вас, поширюючи значення нескінченності та NaN.
markgalassi

@markgalassi Будь ласка, придивіться уважніше: Ви помітите, що neg_infініціалізується до постійного значення . Компілятор подбає про обчислення infзначення. І коли ви використовуєте його як нульове значення для обчислення макс., Перша ітерація, як правило, перезапише його з більшим значенням. Тобто продуктивність навряд чи є проблемою. І ОП запитує конкретно про "наприклад, використовувати негативну нескінченність", і -infсправді є єдиною правильною відповіддю на це. Ви підтримали правильну та корисну відповідь.
cmaster
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.