如何将浮点数初始化为其最大/最小值?

128

如何对浮点数设置绝对最大或最小值?我想通过迭代并捕获最大值来查找数组的最大/最小值。

浮点数还有正无穷和负无穷,我应该使用它们吗?如果是这样,我在代码中如何表示?

注:
- "hard code" 可以翻译为“硬编码”或“直接写入代码”,根据语境选择合适的翻译。 - "array" 可以翻译为“数组”。
5个回答

188
你可以使用在<limits>中定义的std::numeric_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> 中),这些函数可以更好地用于查找数组中的最大或最小值。


我该如何准确地使用它?我需要包含什么?我不认为我以前用过这样的东西。 - Faken
嗯...那个最大元素函数会非常有用...这就是你自学编程而不是正式学习的后果。你最终会重复造轮子50次。这就像上次我学习 ceil() 时一样。谢谢。 - Faken
20
@Yacoby,你可能需要澄清一下 numeric_limits<float>::min() 并不意味着最负值,而是表示最小正数。 - MSN
如果在初始化时不知道类型T,且数组不可用(在线算法),该怎么办?numeric_limits<T>::max()是最小值的良好初始化,但最小值呢?我担心对于整数类型,numeric_limits<T>::max()的否定将无法正常工作,只适用于浮点数。 - killogre
18
C++11新增了numeric_limits<T>::lowest()函数,它返回该类型可能的最小(负)值,以解决这个问题。 - Cornstalks
4
std::numeric_limits<float>::min() 不是可以表示的最小正数值;它是可以表示的最小规范化单精度浮点数。0和这个数字之间还有次规范化数字。特别地,std::numeric_limits<float>::min() 的值为 1.17549e-38,但可以表示的最小次规范化浮点数是 nextafterf(0.0f, 1.0f) == 1.4013e-45f - nibot

63
您可以使用-FLT_MAX(或-DBL_MAX)表示最大幅度的负数,使用FLT_MAX(或DBL_MAX)表示正数。这为您提供了可能的浮点(或双精度)值的范围。
您可能不想使用FLT_MIN,因为它对应于可以用浮点表示的最小幅度的正数,而不是可表示为浮点数中最小的负数值。 FLT_MINFLT_MAX分别对应于std::numeric_limits<float>::min()std::numeric_limits<float>::max()

我想我会实际使用这个版本,因为它更简单易记,并且对我来说更有意义。整数可以使用十六进制进行初始化。不过,最佳答案仍然是最好的,因为该答案还向我介绍了一些非常有用的新函数。 - Faken
3
"[FLT_MIN]对应于可以用浮点数表示的最小幅度正数,但这是不正确的。它是最小的正常数字。还有次正常数。" - nibot
你想要获取FLT_TRUE_MIN来获得实际上最小的浮点数,它对应于std::numeric_limits<float>::denorm_min() - Chris Dodd
1
FLT_MAX和FLT_MIN均在<float.h>头文件中定义。 - Radek Strugalski
FLT_MAX的值是否根据平台而变化? - lpares12

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。


2
我将最大值和最小值初始化,因为有时我想要最小的非零值(例如在无符号整数情况下,我的数据往往有很多不感兴趣的零)。对我来说,初始化似乎是有意义的,而不是执行额外的检查以确保第一个元素不为零。 - Faken
2
@Jerry:C++0x将添加minmax_element来解决您提到的问题。(但是这样就无法忽略零了...) - UncleBens
1
如果在初始化时第一个元素不可用怎么办?这在在线处理中经常发生(例如boost::accumulators)。 - killogre
@killogre:在这种情况下,将您的最小值初始化为std::numeric_limits<T>::max(),将您的最大值初始化为std::numeric_limits<T>::min()肯定是一个合理的选择。 - Jerry Coffin
这种方法在处理可能为NaN的浮点数时存在微妙的问题。如果数组的第一个元素是NaN,则它将返回NaN作为最小值和最大值。然而,如果任何其他元素是NaN,则该元素将被忽略。因此,结果取决于数组中值的顺序,这可能会导致意外情况。使用-inf/inf而不是数组的第一个元素初始化循环就没有这个问题。 - Chris Dodd
显示剩余4条评论

6

要手动查找数组的最小值,您无需知道浮点数的最小值:

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

同样的代码也适用于最大值。


5

我建议您将“最大和最小值”变量初始化为数组中的第一个数字,而不是无穷大。


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