Как обойти противоречивое определение numeric_limits <T>:: min ()? - PullRequest
12 голосов
/ 29 апреля 2009

Предполагается, что черты numeric_limits - это общий способ получения информации различного типа, позволяющий делать такие вещи, как

template<typename T>
T min(const std::vector<T>& vect)
{
    T val = std::numeric_limits<T>::min();

    for(int i=0 ; i<vect.size() ; i++)
        val = max(T, vect[i]);

    return val;
}

Проблема в том, что (по крайней мере, с использованием MS Visual Studio 2008) numeric_limits :: min () возвращает наименьшее отрицательное число, а numeric_limits :: min () возвращает наименьшее положительное число!

Кто-нибудь знает рациональность этого дизайна? Есть ли лучший (рекомендуемый?) Способ использования numeric_limits? В моей специфической функции выше, я, конечно, мог инициализировать T для vect [0], но это не тот ответ, который я ищу ..

См. Также (с плавающей запятой) обсуждение здесь

Ответы [ 7 ]

9 голосов
/ 29 апреля 2009

Вы можете использовать библиотеки Boost. Библиотека Numeric Conversions предоставляет класс bounds, который можно использовать последовательно.

См. Документацию здесь .

6 голосов
/ 20 февраля 2013

Это старая ветка, но есть обновленный ответ:

C ++ 11 добавил функцию lowest() к std::numeric_limits ( Смотрите здесь )

Теперь вы можете позвонить std::numeric_limits<double>::lowest(), чтобы получить минимальное представимое отрицательное значение.

4 голосов
/ 29 апреля 2009

Поведение min () не так уж странно, оно возвращает FLT_MIN, DBL_MIN или INT_MIN (или их соответствующие значения), в зависимости от типа, на котором вы специализируетесь. Таким образом, ваш вопрос должен заключаться в том, почему FLT_MIN и DBL_MIN определены иначе, чем INT_MIN.

К сожалению, я не знаю ответа на этот последний вопрос.

Я подозреваю, что это было определено таким образом для практических целей. Для целых чисел вас обычно волнует переполнение / переполнение, когда минимальное и максимальное значения становятся интересными.

Для чисел с плавающей запятой существует другой вид недостаточного значения, при котором вычисление может привести к значению, которое больше нуля, но меньше наименьшего представимого десятичного числа для этого типа с плавающей запятой. Зная, что наименьшее представимое значение с плавающей запятой позволяет вам обойти проблему. См. Также статью в Википедии о субнормальных / денормальных числах.

1 голос
/ 29 апреля 2009

numeric_limits<int>::min вернул наименьшее отрицательное число, все типы чисел с плавающей запятой, вернет наименьшее положительное число, когда я попробовал его с Sun CC & g ++.

Полагаю, это потому, что «наименьшее» и «минимальное» означают разные вещи с числами с плавающей запятой. Это немного странно, хотя.

Sun CC и g ++ дают одинаковый результат:

короткий: мин: -32768 макс: 32767

int: мин .: -2147483648 макс .: 2147483647

без знака int: мин: 0 макс: 4294967295

длинный: мин: -2147483648 макс: 2147483647

float: мин: 1.17549e-38 макс .: 3.40282e + 38

двойной: мин: 2,22507e-308 макс: 1.79769e + 308

длинный двойной: мин: 3.3621e-4932 макс: 1.18973e + 4932

unsigned short: мин: 0 макс: 65535

без знака int: мин: 0 макс: 4294967295

длинная без знака: мин: 0 макс: 429496729

template<typename T>
void showMinMax()
{
    cout << "min: " << numeric_limits<T>::min() << endl;
    cout << "max: " << numeric_limits<T>::max() << endl;
    cout << endl;
}

int main()
{
cout << "short:";
showMinMax<short>()
...etc...etc..
1 голос
/ 29 апреля 2009

Я не уверен в обосновании, но это ожидаемое поведение. Ну, в том смысле, как это описывает Йосуттис (и, по-видимому, стандарт)!

min (): «Минимальное конечное значение (минимум нормализованное значение для плавающей запятой типы с денормализацией). "

Насколько я могу судить, если тип не целое число (numeric_limits<>::is_integer) и имеет денормализацию (numeric_limits<>::has_denorm) min() вернет наименьшее представимое значение этот тип. В противном случае он вернет наименьшее значение , которое может быть отрицательным.

Для более согласованного интерфейса проверьте библиотеку Boost numeric / translation . В частности, класс черт bounds . Вот фрагмент кода:

cout << "lowest float:" << boost::numeric::bounds<float>::lowest();
cout << "lowest int:  " << boost::numeric::bounds<int>::lowest();

Вы также можете найти полезной библиотеку boost :: integer . Он приносит некоторую целочисленную поддержку C99 (например, int_least16_t) в C ++ и может помочь выбрать тип с наилучшим размером для вашей конкретной потребности. Пример:

boost::uint_t<20>::fast fastest20bits; // fastest unsigned integer that 
                                       // can hold at least 20 bits.
boost::int_max_value_t<100000>::least  // smallest integer that can store
                                       // the value 100000.

Я часто нахожу, что когда мне нужно одно из boost :: numeric / translation или boost :: integer, мне нужны оба.

1 голос
/ 29 апреля 2009

Может быть установлено определение наименьшего значения для пустого вектора. Если вектор пуст, то наименьшего элемента нет.

Предпочитают использовать std :: min_element вместо:

int main()
{
    std::vector<int> v;
    std::generate_n(std::back_inserter(v), 1000, std::rand);

    std::vector<int>::iterator it  = std::min_element(v.begin(), v.end());
    if (it == v.end())
    {
        std::cout << "There is no smallest element" << std::endl;
    }
    else
    {
        std::cout << "The smallest element is " << *it << std::endl;
    }
}
1 голос
/ 29 апреля 2009

Обходной путь будет

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

Конечно, это не объясняет странное поведение numerics_limits :: min (), которое может быть результатом того, что существуют разные минимальные / максимальные границы для целых чисел (min = -2 ^ n, max = 2 ^ n-1) но не для двойников.

...