как мне инициализировать поплавок до его максимального/минимального значения?

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

Есть также положительная и отрицательная бесконечность для поплавков, должен ли я использовать их вместо этого? Если да, то как мне обозначить это в моем коде?


person Faken    schedule 21.04.2010    source источник


Ответы (5)


Вы можете использовать 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>), которые могут быть лучший выбор для поиска наибольшего или наименьшего значения в массиве.

person Yacoby    schedule 21.04.2010
comment
Как мне это использовать? Что мне нужно включить? Я не думаю, что использовал что-то подобное раньше. - person Faken; 21.04.2010
comment
Хм... эта функция max element была бы очень полезна... это то, что происходит, когда вы изучаете программирование самостоятельно, а не формально. В итоге вы изобретаете велосипед 50 раз. Это точно так же, как в прошлый раз, когда я узнал о ceil(). Спасибо. - person Faken; 21.04.2010
comment
@Yacoby, возможно, вы захотите уточнить, что numeric_limits‹float›::min() означает не самое отрицательное значение, а наименьшее положительное. - person MSN; 21.04.2010
comment
Что делать, если тип T неизвестен во время инициализации, а массив недоступен (онлайн-алгоритмы)? numeric_limits‹T›::max() — хорошая инициализация для минимального значения, но как насчет min? Я боюсь, что отрицание numeric_limits‹T›::max() не будет работать должным образом для целочисленных типов, только для чисел с плавающей запятой. - person killogre; 28.05.2012
comment
@killogre: C++11 добавил numeric_limits<T>::lowest(), который возвращает наименьшее (отрицательное) значение, возможное для типа, чтобы решить эту проблему. - person Cornstalks; 08.08.2013
comment
std::numeric_limits<float>::min() не дает наименьшее положительное значение, которое может быть представлено; он дает наименьшее нормальное число с плавающей запятой одинарной точности. Между нулем и этим числом также есть субнормальные числа. В частности, std::numeric_limits<float>::min() дает 1.17549e-38, но наименьшее представимое субнормальное число с плавающей запятой равно nextafterf(0.0f, 1.0f) == 1.4013e-45f. - person nibot; 19.05.2015

Вы можете использовать либо -FLT_MAX (или -DBL_MAX) для максимального отрицательного числа, либо FLT_MAX (или DBL_MAX) для положительного. Это дает вам диапазон возможных значений float (или double).

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

FLT_MIN и FLT_MAX соответствуют std::numeric_limits<float>::min() и std::numeric_limits<float>::max().

person MSN    schedule 21.04.2010
comment
Я думаю, что я буду использовать эту версию на самом деле, ее проще запомнить и она делает меня более сценой. Целые числа я могу просто инициализировать, используя шестнадцатеричное число. Тем не менее, лучший ответ все еще остается, потому что ответ также познакомил меня с некоторыми новыми чрезвычайно полезными функциями. - person Faken; 21.04.2010
comment
[FLT_MIN] соответствует наименьшему положительному числу, которое может быть представлено числом с плавающей запятой. Это неверно. Это наименьшее нормальное число. Есть и субнормальные числа. - person nibot; 19.05.2015
comment
Вы хотите FLT_TRUE_MIN для фактического наименьшего возможного числа с плавающей запятой, что соответствует std::numeric_limits<float>::denorm_min() - person Chris Dodd; 23.07.2016

Нет реальной необходимости инициализировать наименьшее/наибольшее возможное, чтобы найти наименьшее/наибольшее значение в массиве:

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 тогда и только тогда, когда вектор не содержит ненулевых значений.

person Jerry Coffin    schedule 21.04.2010
comment
Но вы получите +1 за это от меня! - person Dan Diplo; 21.04.2010
comment
Я инициализирую максимальное количество минут, потому что иногда мне нужно наименьшее ненулевое значение (например, в случае беззнакового целого числа мои данные имеют много неинтересных нулей). Мне просто кажется, что имеет смысл инициализировать его, а не выполнять дополнительные проверки, чтобы убедиться, что первый элемент не равен нулю. - person Faken; 21.04.2010
comment
@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; } - person UncleBens; 21.04.2010
comment
@Jerry: C++0x добавит minmax_element для решения упомянутой вами проблемы. (Но тогда нельзя будет игнорировать нули...) - person UncleBens; 21.04.2010
comment
Что делать, если первый элемент недоступен во время инициализации? Это часто происходит при онлайн-обработке (например, в boost::accumulators). - person killogre; 28.05.2012
comment
@killogre: В этом случае инициализация вашего минимума до std::numeric_limits<T>::max() и максимума до std::numeric_limits<T>::min(), безусловно, является разумной возможностью. - person Jerry Coffin; 28.05.2012
comment
@Jerry Coffin: это не работает для типов с плавающей запятой, потому что min() возвращает наименьшее положительное значение. для плавающих типов я в настоящее время инициализирую с -max(), но это неправильно для целочисленных типов без знака - person killogre; 29.05.2012
comment
@killogre: Ой, да, я это знаю и всегда забываю. В итоге вы получите уродливое состояние, основанное на std::numeric_limits<T>::is_integer. - person Jerry Coffin; 29.05.2012
comment
В этом подходе есть небольшая проблема для значений с плавающей запятой, которые могут быть NaN. Если первым элементом массива является NaN, то он вернет NaN как минимум и максимум. Однако, если какой-либо другой элемент имеет значение NaN, этот элемент будет проигнорирован. Таким образом, результат становится зависимым от порядка значений в массиве, что может привести к неожиданностям. Инициализация цикла с -inf/inf вместо первого элемента массива не имеет этой проблемы. - person Chris Dodd; 23.07.2016

Чтобы вручную найти минимум массива, вам не нужно знать минимальное значение float:

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

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

person Bill    schedule 21.04.2010

Могу ли я предложить вам инициализировать ваши переменные «максимум и минимум до сих пор» не до бесконечности, а до первого числа в массиве?

person Thomas Padron-McCarthy    schedule 21.04.2010