Подтвердить что ты не робот

Как обойти несогласованное определение numeric_limits <T>:: min()?

Черты 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 <int> :: min() возвращает наименьшее отрицательное число, а numeric_limits <double> :: min() возвращает наименьшее положительное число!

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

Ответ 4

Обходной путь был бы

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

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

Ответ 5

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

Предпочитаете вместо 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;
    }
}

Ответ 6

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

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

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

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

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

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

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/conversion или boost:: integer, мне нужны они оба.

Ответ 7

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

Я думаю, это потому, что "наименьший" и "минимальный" означают разные вещи с номерами с плавающей запятой. Это немного странно.

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

short: min: -32768 max: 32767

int: min: -2147483648 max: 2147483647

unsigned int: min: 0 max: 4294967295

long: мин: -2147483648 max: 2147483647

float: мин: 1.17549e-38 max: 3.40282e + 38

double: min: 2.22507e-308 max: 1.79769e + 308

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

unsigned short: min: 0 max: 65535

unsigned int: min: 0 max: 4294967295

unsigned long: min: 0 max: 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..