2016-05-28 2 views
5

J'affecte 0.4543543234343654632452452525254e-323 à une variable doublea et l'imprime, bien qu'elle soit inférieure à DBL_MIN, elle peut encore être affectée et imprimée.pourquoi un nombre double inférieur à DBL_MIN peut être imprimé?

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

Pourquoi cela se produit-il?

+0

@flatmouse: 'DBL_MIN' est pas la valeur minimum dans le sens de signe, mais dans le sens de la grandeur, la plus petite valeur plus grande (ou plus petite) à zéro. Donc, fondamentalement, le nombre qui est aussi proche de zéro que possible. Le signe n'est pas pertinent car c'est un bit spécifique. – Jack

+0

clic droit> marque et copie le texte de sortie. Pas besoin de capturer la capture d'écran qui peut pourrir si le serveur meurt –

+0

Beaucoup de bonnes choses à virgule flottante dans ce blog (pas le mien) https://randomascii.wordpress.com/2012/05/20/thats-not-normalthe-performance -of-odd-floats/et https://randomascii.wordpress.com/category/floating-point/ –

Répondre

12

En réalité DBL_MIN n'est pas la plus petite valeur mais la plus petite normalized value qui est représentable.

La différence est le premier chiffre avec 1 pour les valeurs normalisées, alors qu'il est 0 pour les nombres dénormaux. Rappelez-vous que denormal numbers pourrait souffrir de problèmes de performance sur le matériel avec une unité de traitement flottante qui n'est pas capable de les gérer dans le matériel.

Mais votre valeur, 0.454354e-323, ce qui correspond à 4.545354e-324 est plus petit que le plus petit nombre de denormal representble avec un double, en effet il devient arrondi à 4.94066e-324 qui est le vrai plus petit nombre qui peut être stocké dans un double.

+0

@flatmouse: 'DBL_MIN' n'est pas le plus petit nombre pouvant être représenté dans une valeur' double', donc il n'y a rien d'étrange dans la sortie du programme OP. – Jack

+1

@flatmouse peut-être vous avez mal lu la question - il me semble que cette réponse répond à la question et la vôtre n'a rien à voir avec elle –

-1

Le comportement IEEE 754-1985 est plus facile à comprendre en examinant directement les bits.

Le following program montre le signe, la mantisse et l'exposant pour chaque nombre et le modèle de bits pour chacun.

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

sortie:

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