为什么 numeric_limits<float>::min() 实际上没有给出尽可能小的浮点数?

Why does numeric_limits<float>::min() not actually give the smallest possible float?

本文关键字:尽可能 浮点数 实际上 limits numeric lt float 为什么 min gt      更新时间:2023-10-16

似乎我们可以简单地推导出小于numeric_limits<float>::min()的浮点数。为什么。如果numeric_limits<float>::min()不应该是最小的正浮点数,那么它应该是什么?

#include <iostream>
#include <limits>
using namespace std;
int main(){
float mind = numeric_limits<float>::min();
float smaller_than_mind = numeric_limits<float>::min()/2;
cout<< ( mind > smaller_than_mind && smaller_than_mind > 0 ) <<endl;
}

在此处运行它:https://onlinegdb.com/ry3AcxjXz

浮点类型的

>min()返回具有格式的全部表达能力的最小正值 - 其有效位数的所有位都可供使用。

较小的正值称为次正值。尽管它们是可表示的,但有效数的高位必然为零。

IEEE-754 64 位二进制浮点格式表示一个带符号的数字(+ 或 -,编码为 0 或 1)、一个指数(-1022 到 +1023,编码为 1 到 2046,加上 0 和 2047 作为特殊情况)和一个 53 位有效数(用 52 位加上指数字段中的线索编码)。

对于正常值,指数字段为 1 到 2046(表示 -1022 到 +1023 的指数),有效数(二进制)为 1.xxx...xxx,其中xxx...xxx 表示另外 52 位。在所有这些值中,有效位数的最低位的值是最高有效位(其中的前 1 位)值的2-52倍。

对于次正规值,指数字段为 0。这仍然表示 -1022 的指数,但这意味着有效位数的高位为 0。意义现在 0.xxx...xxx. 由于在此范围内使用越来越低的值,有效数的更多前导位变为零。现在,有效位数的最低位的值大于最高有效位值的2-52倍。在此区间内,您不能像在正常区间中那样精细地调整数字,因为并非有效位数的所有位都可用于任意值 - 某些前导位固定为 0 以设置刻度。

因此,处理此范围内的数字时发生的相对误差往往大于正常范围内的相对误差。浮点格式具有此次正态范围,因为如果没有,数字将恰好在最小正态值处切断,并且该正态值与零之间的差距将是一个巨大的相对跳跃 - 单步完成值的 100%。通过包括次正规数,相对误差会逐渐增加,并且绝对误差从这一点开始保持不变,直到达到零。

重要的是要知道正常范围的底部在哪里。min()告诉你这一点。denorm_min()告诉您最终的最小正值。

根据 en.cppreference.com:

对于具有非规范化的浮点类型,min 返回最小值 正归一化值。请注意,此行为可能是意外的, 特别是与积分类型的最小值行为相比时。

float是一种具有非规范化的类型,即有关规范化浮点数的信息。

因为numeric_limits::min返回"对于具有次正规数的浮点类型,返回最小正规范化值"。 您可以将其除以 2,并在某些系统上获得一个次正态(在某些平台上也称为非正态)数字。 这些数字不存储float类型的完整精度,但允许存储否则将变为 0.0 的值。