【问题标题】:Why does numeric_limits<float>::min() not actually give the smallest possible float?为什么 numeric_limits<float>::min() 实际上没有给出尽可能小的浮点数?
【发布时间】:2018-01-04 01:07:18
【问题描述】:

似乎我们可以轻松推导出小于numeric_limits&lt;float&gt;::min() 的浮点数。为什么。如果numeric_limits&lt;float&gt;::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

【问题讨论】:

    标签: c++ floating-point


    【解决方案1】:

    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() 告诉你最终的最小正值。

    【讨论】:

      【解决方案2】:

      根据en.cppreference.com:

      对于具有非规范化的浮点类型,min 返回最小值 正标准化值。请注意,这种行为可能是意料之外的, 尤其是与整数类型的 min 行为相比时。

      float 是一种非规范化类型,information 是规范化浮点数。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • @EricPostpischil 已更新。我盯着英特尔文档太久了。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-09
        • 1970-01-01
        • 1970-01-01
        • 2019-12-15
        • 1970-01-01
        • 2019-02-23
        • 1970-01-01
        相关资源
        最近更新 更多