为什么将 1 添加到 numeric_limits<float>::min() return 1?

Why does adding 1 to numeric_limits<float>::min() return 1?

为什么从 float max returns 中减去 1 是一个合理的值,而在 float min returns 1 中加 1?

我认为如果您添加或减去一个小于特定大小的 epsilon 的值,那么什么也不会发生,也不会增加或减少。

这是我在 x86_64.

上使用没有标志的 g++ 和 运行 编译的代码
#include <limits>
#include <iostream>

int main() {
    float min = std::numeric_limits<float>::min() + 1;
    float max = std::numeric_limits<float>::max() - 1;

    std::cout << min << std::endl << max << std::endl;
    return 0;
}

输出这个:

1
3.40282e+38

我希望它输出这个:

-3.40282e+38
 3.40282e+38

std::numeric_limits<float>::min() returns 最小的归一化正值。要获取没有比它低的值,请使用 std::numeric_limits<float>::lowest().

https://en.cppreference.com/w/cpp/types/numeric_limits/min

min is the smallest-magnitude positive normalized float, a very tiny positive number (about 1.17549e-38), not a negative number with large magnitude. Notice that the - is in the exponent, and this is scientific notation. e-38 means 38 zeros after the decimal point. Try it out on https://www.h-schmidt.net/FloatConverter/IEEE754.html 玩转二进制 float.

std::numeric_limits<float>::min() 是标准化的 float 的最小 幅度 ,而不是 -maxCppReference 甚至有一个关于这可能令人惊讶的注释。

Do you know why that was picked to be the value for min() rather than the lowest negative value? Seems to be an outlier with regards to all the other types.

numeric_limits<T> 中的某些复杂功能,如 lowestdenorm_min 是 C++11 中的新功能。大多数定义什么的选择大多遵循C。历史上的C重视经济并且没有定义很多不同的名称。 (在古老的计算机上越小越好,而且 C 可以访问的全局命名空间中的东西也越少。)

float 类型通常1 围绕 0 对称(sign/magnitude 表示),因此 C 没有单独的命名常量用于最负的 float / double / 长双。只有 FLT_MAXFLT_MIN CPP 宏。 C 没有模板,因此您知道何时编写 FP 代码,并且可以根据需要在适当的常量上使用 -

如果您只需要几个命名常量,最有趣的三个是:

  • FLT_EPSILON 告诉您可用精度(尾数位):nextafter(1.0, +INF) - 1.0
  • FLT_MIN / FLT_MAX 有限浮点数的最小(归一化)和最大幅度。这主要取决于浮点数有多少个指数位。

    由于两个原因,它们在 1.0 附近不太对称:FLT_MAX 中的全一尾数,以及逐渐下溢(次正规)占据最低指数场(0 有偏差),但 FLT_MIN 忽略次正规。对于 IEEE754 binary32 floatFLT_MIN * FLT_MAX 约为 3.99999976。 (出于性能原因,您通常希望避免次正规,因此您有逐渐下溢的空间,因此 FLT_MIN 不是 denorm_min 是有道理的)

(有趣的事实:0.0 是次正规的特例:指数字段 = 0 表示尾数为 0.xxx 而不是 1.xxx)。

脚注 1: CppReference 指出 C++11 std::numeric_limits<T>::lowest() 可能 不同于 -max适用于第 3 方 FP 类型,但不适用于标准 C++ FP 类型。

lowest 你想要的:最负的有限值。它在整数和 FP 类型中作为最负值是一致的,因此例如您可以将它用作模板搜索循环的初始值设定项,该循环使用 std::min 查找数组中的最小值。

C++11 还引入了 denorm_min,FP 类型的最小正次正规 aka 非正规值。在 IEEE754 中,对象表示的所有位都是 0,除了尾数低位中的 1。


1.0 + 1.17549e-38(四舍五入到最接近的 float 后)的浮点结果正好是 1.0 min 是低于 std::numeric_limits<float>::epsilon,因此当添加到 1.0.

时,整个更改会因舍入误差而丢失

因此,即使您以全精度打印浮点数(或作为十六进制浮点数),它也将是 1.0。但是您只是使用 cout 的默认格式进行打印,该格式四舍五入到某些有限的精度,例如 6 位十进制数字。 https://en.cppreference.com/w/cpp/io/manip/setprecision

(问题的早期版本包括 min ~= 1.17549e-38 的数值;这个答案开始解决这个混淆问题,我没有费心去完全重写这些部分)。