如何解决numeric_limits<T>::min()不一致的定义?

13

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],但那不是我想要的答案..

另请参阅(浮点特定)讨论此处


你的例子中有两个bug。
  1. 函数应该被称为max(),因为它计算最大元素。
  2. 行"val = max(T, vect[i])" 应该是 "val = max(val, vect[i])"。
- TonJ
7个回答

9
你可以使用Boost库。Numeric Conversions库提供了一个名为bounds的类,可用于一致地转换数据类型。
查看文档这里

6

这是一个旧的帖子,但有一个更新的答案:

C++11在std::numeric_limits中添加了一个lowest()函数(请看这里)

因此,您现在可以调用std::numeric_limits<double>::lowest()来获取最低可表示的负值。


4
min()的行为并不奇怪,它返回FLT_MIN、DBL_MIN或INT_MIN(或其相应的值),具体取决于您使用的类型。所以你的问题应该是为什么FLT_MIN和DBL_MIN与INT_MIN定义不同。
不幸的是,我不知道后一个问题的答案。
我怀疑它是出于实际目的而定义的。对于整数,您通常关心溢出/下溢,其中最小值和最大值变得重要。
对于浮点数,存在一种不同类型的下溢,即计算可能导致一个值大于零,但小于该浮点类型的最小可表示十进制数。知道最小可表示浮点值可以让您解决这个问题。另请参阅维基百科上有关subnormal/denormal数字的文章。

1
一个解决方法是:
double val = -std::numeric_limits<double>::max();

当然,这并不能解释numerics_limits::min()的奇怪行为,这可能是由于整数有不同的最小/最大边界(最小值=-2^n,最大值=2^n-1),但双精度浮点数没有。


std::numeric_limits<int>::max() == -std::numeric_limits<int>::min() 吗? - Martin York
我不这么认为 - 正如我所写的,例如32位数据类型的最小值为-2^31,最大值为2^31-1。这代表了最大的负/正整数值 - gcc证实了这一点:“min:-2147483648,max:2147483647”。 - schnaader
不,我的代碼是針對雙精度浮點型的,而不是整型。對於雙精度浮點型,行為是不同的(min 函數返回最小正雙精度浮點型的值) - 這就是求問者問題的關鍵所在。因此,要得到最大負值(期望的 min 函數行為),需要使用這段代碼。當然,這並不適用於所有類型或模板,只適用於特殊的雙精度浮點型情況。 - schnaader
Boost Bounds (1.38)中关于lowest的说明为:"返回最小的有限值,当T是整数类型时等同于numeric_limits<T>::min(),当T是浮点数类型时等同于-numeric_limits<T>::max()"。详情请参见http://www.boost.org/doc/libs/1_38_0/libs/numeric/conversion/doc/html/boost_numericconversion/bounds___traits_class.html。 - Alessandro Jacopson

1

对于空向量的最小值定义可以有争议。如果向量为空,则没有最小元素。

最好使用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

我不确定其背后的理念,但这是预期行为。也就是说,这就是Josuttis(和标准)所描述的方式!

min():「最小有限值(对于带有非规格化值的浮点类型来说是最小的规格化值)。」

据我所知,如果该类型不是整数 (numeric_limits<>::is_integer) 并且 具有非规格化值 (numeric_limits<>::has_denorm),那么 min() 将返回该类型所能表示的最小值。否则,它将返回最小的 - 这可能是负数。

如需更一致的界面,请查看Boost numeric/conversion库。特别是 bounds traits class。以下是一个摘录:

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/conversion或boost::integer中的一个时,我需要它们两个。


1

numeric_limits<int>::min 返回了最小的负数,而所有浮点数类型在我使用 Sun CC 和 g++ 时返回了最小的正数。

我猜这是因为“最小”和“最小值”在浮点数中意味着不同的事情。虽然这有点奇怪。

Sun CC 和 g++ 都产生了相同的结果:

短整型:min: -32768 max: 32767 整型:min: -2147483648 max: 2147483647 无符号整型:min: 0 max: 4294967295 长整型:min: -2147483648 max: 2147483647 浮点型:min: 1.17549e-38 max: 3.40282e+38 双精度型:min: 2.22507e-308 max: 1.79769e+308 长双精度型:min: 3.3621e-4932 max: 1.18973e+4932 无符号短整型:min: 0 max: 65535 无符号整型:min: 0 max: 4294967295 无符号长整型: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..

1
奇怪的是,numeric_limits<double>::min在这里返回一个非常小的正数(g++ 3.4.5)。也许这取决于版本/操作系统/实现。 - schnaader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接