为什么可以打印小于 DBL_MIN 的双数?

why a double number less than DBL_MIN can be printed?

我把0.4543543234343654632452452525254e-323赋值给一个double变量a打印出来,虽然小于DBL_MIN,还是可以赋值打印出来的。

DBL_MAX: 1.79769e+308
FLT_MAX: 3.40282e+38
DBL_MIN: 2.22507e-308
FLT_MIN: 1.17549e-38
a: 4.94066e-324

为什么会这样?

实际上DBL_MIN不是最小值而是可表示的最小值normalized value

不同之处在于,规范化值的前导数字为 1,非规范化数字的前导数字为 0。请注意,denormal numbers 可能会遇到无法在硬件中管理浮动处理单元的硬件的严重性能问题。

但是您的值 0.454354e-323 对应于 4.545354e-324 小于用 double 表示的最小非正规数,实际上它四舍五入为 4.94066e-324是可以存储在 double.

中的最小实数

直接查看位更容易理解 IEEE 754-1985 行为。

following program 显示每个数字的符号、尾数和指数以及每个数字的位模式。

#include <iostream>
#include <limits>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <string>
#include <tuple>
#include <sstream>
#include <cmath>

using Values = std::tuple<double,std::string>;
using MyMap = std::unordered_map<std::string,Values>;

std::string convert_to_string(double val)
{
    auto ptr{reinterpret_cast<const unsigned long long*>(&val)};
    auto ival{*ptr};
    unsigned long long mask{1ULL << 63};
    std::string bitstring;
    for (size_t i{0}; i<64; ++i) {
        auto bitval{(ival&mask)>0};
        mask >>= 1;
        bitval? bitstring.push_back('1') : bitstring.push_back('0');
    }

    return bitstring;
}

std::ostream& operator<<(std::ostream& os,std::pair<std::string,Values> mypair)
{
    auto name{mypair.first};
    auto values{mypair.second};
    auto dvalue{std::get<0>(values)};
    auto bitsetvalue{std::get<1>(values)};
    char sign_symbol{bitsetvalue.substr(0,1)=="0"?'+':'-'};
    std::bitset<1> sign{bitsetvalue.substr(0,1)};
    std::bitset<11> biased_exponent{bitsetvalue.substr(1,11)};
    std::bitset<52> mantissa{bitsetvalue.substr(12,52)};
    auto mantissa_value{mantissa.to_ullong()};
    double mantissa_value_double{static_cast<double>(mantissa_value)};
    auto biased_exponent_value{static_cast<signed long long>(biased_exponent.to_ulong())};
    bool denormal{biased_exponent_value==0};
    std::string denormal_text{denormal?"denormal":""};
    signed long long exponent_value{denormal?-1022:biased_exponent_value-1023};
    std::string mantissa_with_leading_digit{std::string((denormal?"0.":"1.")) + mantissa.to_string()};
    double mantissa_with_leading_digit_value{double{denormal?0.0F:1.0F}+(mantissa_value_double * std::pow(2.0F,-52.0F))};
    std::bitset<11> unbiased_exponent{static_cast<unsigned long long>(std::abs(exponent_value))};
    char exponent_sign_symbol{exponent_value<0?'-':' '};

    std::cout << std::setw(60) << name << std::setw(20) << dvalue << '\n';
    std::cout << std::setw(60) << "Binary  (biased   exponent, hidden  leading binary digit)" << std::setw(30) << sign << std::setw(15) << biased_exponent << std::setw(10) << denormal_text << std::setw(60) << mantissa << '\n';
    std::cout << std::setw(60) << "Binary  (unbiased exponent, visible leading binary digit)" << std::setw(30) << sign << std::setw(4) << exponent_sign_symbol << unbiased_exponent << std::setw(10) << denormal_text << std::setw(60) << mantissa_with_leading_digit << '\n';
    std::cout << std::setw(60) << "Decimal (biased   exponent)                              " << std::setw(30) << sign_symbol << std::setw(15) << biased_exponent_value << std::setw(10) << denormal_text << std::setw(60) << mantissa_with_leading_digit_value << '\n';
    std::cout << std::setw(60) << "Decimal (unbiased exponent)                              " << std::setw(30) << sign_symbol << std::setw(15) << exponent_value << std::setw(10) << denormal_text << std::setw(60) << mantissa_with_leading_digit_value << '\n';
    std::cout << std::setw(50) << mantissa_with_leading_digit_value << " * 2**" << std::setw(5) << exponent_value << "   =   " << std::setw(12) << mantissa_with_leading_digit_value*std::pow(2.0F,exponent_value) << '\n';
    std::cout << std::setw(180) << std::setfill('-') << '\n' << std::setfill(' ') << "\n\n\n";

    return os;
}

int main()
{
    double max_double = std::numeric_limits<double>::max();
    double lowest_double = std::numeric_limits<double>::min();
    double stored_value{0.4543543234343654632452452525254e-323};


    MyMap values{
        {"Lowest",std::make_tuple(lowest_double, convert_to_string(lowest_double))},
        {"Highest",std::make_tuple(max_double, convert_to_string(max_double))},
        {"0.4543543234343654632452452525254e-323",std::make_tuple(stored_value, convert_to_string(stored_value))}

    };

    std::cout << std::setw(60) << "Variable name" << std::setw(20) << "Decimal value" << std::setw(10) << "Sign" << std::setw(15) << "Exponent" << std::setw(10) << "Exp. Rule" << std::setw(60) << "Mantissa" << std::setw(30) << '\n';
    std::cout << std::setw(180) << std::setfill('-') << '\n' << std::setfill(' ');
    for (auto& i : values)
        std::cout << i;

    return 0;
}

输出:

                                               Variable name       Decimal value      Sign       Exponent Exp. Rule                                                    Mantissa
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
                                                      Lowest        2.22507e-308
   Binary  (biased   exponent, hidden  leading binary digit)                             0    00000000001                  0000000000000000000000000000000000000000000000000000
   Binary  (unbiased exponent, visible leading binary digit)                             0   -01111111110                1.0000000000000000000000000000000000000000000000000000
   Decimal (biased   exponent)                                                           +              1                                                                     1
   Decimal (unbiased exponent)                                                           +          -1022                                                                     1
                                                 1 * 2**-1022   =   2.22507e-308
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



                                                     Highest        1.79769e+308
   Binary  (biased   exponent, hidden  leading binary digit)                             0    11111111110                  1111111111111111111111111111111111111111111111111111
   Binary  (unbiased exponent, visible leading binary digit)                             0    01111111111                1.1111111111111111111111111111111111111111111111111111
   Decimal (biased   exponent)                                                           +           2046                                                                     2
   Decimal (unbiased exponent)                                                           +           1023                                                                     2
                                                 2 * 2** 1023   =   1.79769e+308
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



                      0.4543543234343654632452452525254e-323        4.94066e-324
   Binary  (biased   exponent, hidden  leading binary digit)                             0    00000000000  denormal        0000000000000000000000000000000000000000000000000001
   Binary  (unbiased exponent, visible leading binary digit)                             0   -01111111110  denormal      0.0000000000000000000000000000000000000000000000000001
   Decimal (biased   exponent)                                                           +              0  denormal                                                 2.22045e-16
   Decimal (unbiased exponent)                                                           +          -1022  denormal                                                 2.22045e-16
                                       2.22045e-16 * 2**-1022   =   4.94066e-324
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------