2016-05-28 19 views
5

I zuweisen 0.4543543234343654632452452525254e-323 zu einer double Variable a und drucken Sie es, obwohl es weniger als DBL_MIN ist, kann es noch zugeordnet und gedruckt werden.Warum kann eine Doppelnummer kleiner als DBL_MIN gedruckt werden?

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

Warum das passiert?

+0

@flatmouse: 'DBL_MIN' ist nicht der Minimalwert im Sinne von Zeichen, sondern im Sinne von Größe, der kleinste Wert größer (oder kleiner) als Null ist. Also, im Grunde die Zahl, die so nah wie möglich an Null ist. Das Zeichen ist irrelevant, da es ein bestimmtes Bit ist. – Jack

+0

Rechtsklick> Markieren und kopieren Sie den ausgegebenen Text. Keine Notwendigkeit, den Screenshot zu erfassen, der verrotten kann, wenn der Server stirbt –

+0

Viele gute Gleitkomma-Sachen in diesem Blog (nicht meiner) https://randomascii.wordpress.com/2012/05/20/thats-not-normalthe-performance -of-odd-floats/und https://randomascii.wordpress.com/category/floating-point/ –

Antwort

12

Eigentlich ist DBL_MIN nicht der kleinste Wert, aber der kleinste normalized value, der darstellbar ist.

Der Unterschied ist die führende Ziffer mit ist 1 für normalisierte Werte, während es 0 für denormal Zahlen ist. Beachten Sie, dass denormal numbers unter schwerwiegenden Leistungsproblemen auf Hardware mit schwebender Verarbeitungseinheit leiden kann, die nicht in der Lage ist, sie in Hardware zu verwalten.

Aber Ihr Wert, 0.454354e-323, die 4.545354e-324 entspricht, ist kleiner als der kleinste denormal Zahl representble mit einem double, in der Tat wird es 4.94066e-324 abgerundet, die die reale kleinste Zahl ist, die in einem double gespeichert werden können.

+0

@flatmouse: 'DBL_MIN' ist nicht die kleinste Zahl, die in einem' double'-Wert dargestellt werden kann, so dass nichts in der Ausgabe des OP-Programms merkwürdig ist. – Jack

+1

@flatmouse vielleicht hast du die Frage falsch verstanden - es scheint mir, dass diese Antwort die Frage beantwortet und deine hat nichts damit zu tun –

-1

Das Verhalten von IEEE 754-1985 ist leichter zu verstehen, wenn man die Bits direkt betrachtet.

Die following program zeigt das Vorzeichen, die Mantisse und den Exponenten für jede Zahl und das Bitmuster für jede Zahl.

#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; 
} 

Ausgang:

           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 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------