як я ініціалізую поплавок на його значення max / min?


100

Як я жорстко кодую абсолютне максимальне або мінімальне значення для поплавця чи подвійних? Я хочу шукати максимум / хв масиву, просто перебираючи і переймаючи найбільший.

Існують також позитивні та негативні нескінченності для поплавців, чи варто використовувати їх замість них? Якщо так, то як я позначу це у своєму коді?

Відповіді:


151

Ви можете використовувати std::numeric_limitsвизначене в, <limits>щоб знайти мінімальне або максимальне значення типів (доки існує спеціалізація для типу). Ви також можете скористатися нею для отримання нескінченності (і поставити -фронт для негативної нескінченності).

#include <limits>

//...

std::numeric_limits<float>::max();
std::numeric_limits<float>::min();
std::numeric_limits<float>::infinity();

Як зазначається в коментарях, min()повертає найменше можливе позитивне значення. Іншими словами, позитивне значення, найближче до 0, яке можна представити. Найменше можливе значення - мінус максимально можливого значення.

Звичайно, є std::max_elementі функції min_element (визначені в <algorithm>), які можуть бути кращим вибором для пошуку найбільшого або найменшого значення масиву.


Як мені це точно використовувати? Що мені потрібно включити? Я не думаю, що раніше я використовував щось подібне.
Факен

Гм ... що функція max елементів була б дуже корисною ... це відбувається, коли ви дізнаєтесь кодування самостійно, а не формально. Ви закінчите винаходити колесо 50 разів. Це так само, як востаннє, коли я дізнався про ceil (). Дякую.
Факен

18
@Yacoby, ви можете уточнити, що numeric_limits <float> :: min () не означає найбільш негативне значення, це означає найменше додатне.
MSN

13
@killogre: додано C ++ 11 numeric_limits<T>::lowest(), що повертає найменше (негативне) значення для типу, щоб вирішити цю проблему.
Cornstalks

3
std::numeric_limits<float>::min()ніяк НЕ дає найменше позитивне значення , яке може бути представлено; він дає найменше нормальне одноточне число з плаваючою точкою. Існують також субнормальні числа між нулем і цим числом. Зокрема, std::numeric_limits<float>::min()дає, 1.17549e-38але найменший представницький субнормальний поплавок nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot

45

Ви можете використовувати -FLT_MAX(або -DBL_MAX) для максимальної негативної чисельності та FLT_MAX(або DBL_MAX) для додатної. Це дає діапазон можливих значень поплавкового (або подвійного) значення.

Ви, мабуть, не хочете користуватися FLT_MIN; воно відповідає найменшій додатній величині за величиною, яка може бути представлена ​​поплавком, а не найменше негативне значення, що може бути представлене поплавком.

FLT_MINі FLT_MAXвідповідають std::numeric_limits<float>::min()і std::numeric_limits<float>::max().


Думаю, я використаю цю версію насправді, її простіше запам’ятати та зробить для мене більше сцени. Цілі я можу просто ініціалізувати, використовуючи шістнадцятковий. Хоча найкраща відповідь все ще залишається, оскільки відповідь також познайомила мене з деякими новими надзвичайно корисними функціями.
Faken

2
"[ FLT_MIN] відповідає найменшій додатній величині за величиною, яка може бути представлена ​​поплавком" - Це неправда . Це найменше нормальне число. Існують також субнормальні числа.
nibot

Ви хочете FLT_TRUE_MINотримати найменший можливий поплавок, який відповідаєstd::numeric_limits<float>::denorm_min()
Кріс Додд

17

Немає реальної потреби ініціалізуватися до найменшого / найбільшого можливого, щоб знайти найменший / найбільший у масиві:

double largest = smallest = array[0];
for (int i=1; i<array_size; i++) {
    if (array[i] < smallest)
        smallest = array[i];
    if (array[i] > largest0
        largest= array[i];
}

Або якщо ви це робите не один раз:

#include <utility>

template <class iter>
std::pair<typename iter::value_type, typename iter::value_type> find_extrema(iter begin, iter end) {
    std::pair<typename iter::value_type, typename iter::value_type> ret;
    ret.first = ret.second = *begin;
    while (++begin != end) {
        if (*begin < ret.first)
           ret.first = *begin;
        if (*begin > ret.second)
           ret.second = *begin;
   }
   return ret;
}

Недолік надання зразкового коду - я бачу, що інші вже запропонували таку ж ідею.

Зауважте, що хоча стандарт має min_element та max_element, їх використання потребує сканування даних двічі, що може бути проблемою, якщо масив взагалі великий. Останні стандарти вирішили цю проблему, додавши а std::minmax_element, який робить те саме, що і find_extremaвище (знайдіть як мінімум, так і максимальний елемент у колекції за один прохід).

Редагувати: вирішення проблеми пошуку найменшого ненульового значення в масиві без підпису: спостерігайте за тим, що неподписані значення "обертаються", коли вони досягають крайності. Щоб знайти найменше ненульове значення, ми можемо відняти одне з кожного для порівняння. Будь-які нульові значення "обернуться" до найбільшого можливого значення для типу, але зв'язок між іншими значеннями збережеться. Після того, як ми закінчимо, ми, очевидно, повернемо назад значення, яке ми знайшли.

unsigned int min_nonzero(std::vector<unsigned int> const &values) { 
    if (vector.size() == 0)
        return 0;
    unsigned int temp = values[0]-1;
    for (int i=1; i<values.size(); i++)
        if (values[i]-1 < temp)
            temp = values[i]-1;
    return temp+1;
}

Зверніть увагу, що для початкового значення все ще використовується перший елемент, але нам все ще не потрібен код "спеціального випадку" - оскільки це буде завершуватися до найбільшого можливого значення, будь-яке ненульове значення буде порівнюватися як менше. Результатом буде найменше ненульове значення, або 0, якщо і тільки якщо вектор не містив ненульових значень.


Але ви отримуєте +1 за це від мене!
Dan Diplo

1
Я ініціалізую максимум хвилин, тому що іноді мені хочеться найменшого ненульового значення (наприклад, у випадку без підписаного цілого числа, наприклад, мої дані мають велику кількість нецікавих нулів). Мені здається, має сенс ініціалізувати це, а не проводити додаткові перевірки, щоб переконатися, що перший елемент не дорівнює нулю.
Faken

@Faken: Вже тоді ви можете визначити функцію порівняння, яка розглядає нуль як найбільше можливе значення, тому ви все одно можете використовувати std::min_element:bool less_ignoring_zero(unsigned a, unsigned b) { if (a == 0) return false; if (b == 0) return true; return a < b; }
UncleBens

2
@Jerry: C ++ 0x додасть minmax_element для вирішення вказаної вами проблеми. (Але тоді ігнорувати нулі не вдасться ...)
UncleBens

1
Що робити, якщо перший елемент недоступний під час ініціалізації? Це трапляється багато в онлайновій обробці (як у boost :: акумуляторах)
killogre

5

Щоб вручну знайти мінімум масиву, вам не потрібно знати мінімальне значення float:

float myFloats[];
...
float minimum = myFloats[0];
for (int i = 0; i < myFloatsSize; ++i)
{
  if (myFloats[i] < minimum)
  {
    minimum = myFloats[i];
  }
}

І аналогічний код для максимального значення.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.