sil*_*nia 0 c++ floating-point gcc x86-64 floating-accuracy
为什么从 float max 中减去 1 会返回一个合理的值,而向 float min 中加 1 会返回 1?
我认为,如果您添加或减去一个小于该特定量级的 epsilon 的值,则不会发生任何事情,也不会增加或减少。
这是我用没有标志的 g++ 编译并在 x86_64 上运行的代码。
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出这个:
1
3.40282e+38
Run Code Online (Sandbox Code Playgroud)
我希望它输出这个:
-3.40282e+38
3.40282e+38
Run Code Online (Sandbox Code Playgroud)
std::numeric_limits<float>::min()返回最小的归一化正值。要获取没有低于它的值的值,请使用std::numeric_limits<float>::lowest().
https://en.cppreference.com/w/cpp/types/numeric_limits/min
min是最小幅度正归一化浮点数,一个非常小的正数(约1.17549e-38),而不是具有大幅度的负数。请注意,-是在指数中,这是科学记数法。 e-38表示小数点后 38 个零。在https://www.h-schmidt.net/FloatConverter/IEEE754.html上试一试,以二进制float.
std::numeric_limits<float>::min()是归一化的最小幅度float,不是-max。 CppReference甚至有关于这可能令人惊讶的注释。
你知道为什么它被选为 min() 的值而不是最低的负值吗?似乎是所有其他类型的异常值。
C++11中numeric_limits<T>类似lowest和denorm_min新的一些复杂性。定义什么的选择大多遵循C。Historical C重视经济,并没有定义很多不同的名称。(在古老的计算机上,越小越好,而且全局命名空间中的内容也更少,而 C 可以访问所有这些内容。)
浮点类型通常是1围绕 0 对称(符号/大小表示),因此 C 没有单独的命名常量用于最负浮点数/双精度数/长双精度数。JustFLT_MAX和FLT_MINCPP 宏。C 没有模板,因此您知道何时编写 FP 代码,并且可以-在必要时在适当的常量上使用 a 。
如果您只想拥有一些命名常量,那么最有趣的三个是:
FLT_EPSILON 告诉您可用的精度(尾数位): nextafter(1.0, +INF) - 1.0FLT_MIN/ FLT_MAXmin(归一化)和有限浮点数的最大值。这主要取决于浮点数具有多少指数位。
由于两个原因,它们在 1.0 附近不是很对称:FLT_MAX 中的尾数为全 1,逐渐下溢(次法线)占据最低指数场(0 带偏差),但FLT_MIN忽略次法线。 FLT_MIN * FLT_MAX对于IEEE754 binary32 大约是3.99999976float。(出于性能原因,您通常希望避免低于正常值,因此您有逐渐下溢的空间,因此 FLT_MIN 不是denorm_min)
(有趣的事实:0.0是次正规的特例:指数字段 = 0 意味着尾数为 0.xxx 而不是 1.xxx)。
脚注 1: CppReference 指出 C++11可能与3rd-party FP 类型不同,但不适用于标准 C++ FP 类型。std::numeric_limits<T>::lowest() -max
lowest 是你想要的:最负的有限值。它在整数和 FP 类型中一致作为最负值,因此例如,您可以将其用作模板化搜索循环的初始std::min值设定项,用于查找数组中的最小值。
C++11 还引入denorm_min了 FP 类型的最小正次正规值,也就是非正规值。在 IEEE754 中,对象表示具有除尾数低位中的 1 之外的所有位 0。
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的数值;这个答案开始解决该混淆问题,我没有费心完全重写这些部分)。