![](/img/trans.png)
[英]Why does numeric_limits::min return a negative value for int but positive values for float/double?
[英]Why does adding 1 to numeric_limits<float>::min() return 1?
為什么從 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;
}
輸出這個:
1
3.40282e+38
我希望它是 output 這個:
-3.40282e+38
3.40282e+38
std::numeric_limits<float>::min()
返回最小的標准化正值。 要獲取沒有值低於它的值,請使用std::numeric_limits<float>::lowest()
。
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() 的值而不是最低的負值嗎? 似乎是所有其他類型的異常值。
numeric_limits<T>
中的一些復雜性(例如lowest
和denorm_min
)在 C++11 中是新的。 大多數定義內容的選擇大多遵循 C。 歷史上的 C 重視經濟,並沒有定義很多不同的名稱。 (在古代計算機上越小越好,而且全局命名空間中的東西也更少,這是 C 可以訪問的所有內容。)
浮點類型通常是1圍繞 0 對稱(符號/幅度表示),因此 C 沒有單獨的命名常量用於最負的浮點/雙精度/長雙精度。 只有FLT_MAX
和FLT_MIN
CPP 宏。 C 沒有模板,因此您知道何時編寫 FP 代碼並且可以在必要時在適當的常量上使用-
。
如果您只需要幾個命名常量,那么最有趣的三個是:
FLT_EPSILON
告訴您可用的精度(尾數位): nextafter(1.0, +INF) - 1.0
FLT_MIN
/ FLT_MAX
最小(標准化)和最大有限浮點數。 這主要取決於浮點數有多少指數位。
它們在 1.0 附近不太對稱,原因有兩個:FLT_MAX 中的尾數全為一,逐漸下溢(次正規)占據最低指數場(0 有偏差),但FLT_MIN
忽略次正規。 FLT_MIN * FLT_MAX
對於IEEE754 binary32 float
約為 3.99999976。 (出於性能原因,您通常希望避免次正規,因此您有逐漸下溢的空間,因此 FLT_MIN 不是denorm_min
是有道理的)
(有趣的事實: 0.0
是次正規的特例:指數字段 = 0 意味着尾數為 0.xxx 而不是 1.xxx)。
腳注 1: CppReference 指出 C++11 std::numeric_limits<T>::lowest()
對於第 3 方 FP 類型可能與-max
不同,但不適用於標准 C++ FP 類型。
lowest
的是你想要的:最負的有限值。 它在 integer 和 FP 類型中是一致的,因為它是最負值,因此例如,您可以將它用作模板化搜索循環的初始化程序,該循環使用std::min
來查找數組中的最小值。
C++11 還引入了denorm_min
,即 FP 類型的最小正次正規又名非正規值。 在 IEEE754 中,object 表示除尾數低位中的 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 的數值;這個答案開始解決這個混淆,我沒有費心完全重寫這些部分)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.