簡體   English   中英

為什么將 1 添加到 numeric_limits<float> ::min() 返回 1?</float>

[英]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()

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() 的值而不是最低的負值嗎? 似乎是所有其他類型的異常值。

numeric_limits<T>中的一些復雜性(例如lowestdenorm_min )在 C++11 中是新的。 大多數定義內容的選擇大多遵循 C。 歷史上的 C 重視經濟,並沒有定義很多不同的名稱。 (在古代計算機上越小越好,而且全局命名空間中的東西也更少,這是 C 可以訪問的所有內容。)

浮點類型通常是1圍繞 0 對稱(符號/幅度表示),因此 C 沒有單獨的命名常量用於最負的浮點/雙精度/長雙精度。 只有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忽略次正規。 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM