Question

Je voudrais avoir le nombre le plus proche inférieur à 1,0 en virgule flottante. En lisant l'article de wikipedia sur IEEE-754 j'ai réussi à trouver que la représentation binaire de 1,0 est 3FF0000000000000, de sorte que la valeur la plus proche est en fait à double 0x3FEFFFFFFFFFFFFF.

La seule façon que je connaisse pour initialiser un double avec ces données binaires est ceci:

double a;
*((unsigned*)(&a) + 1) = 0x3FEFFFFF;
*((unsigned*)(&a) + 0) = 0xFFFFFFFF;

Ce qui est assez lourd à utiliser.

Y at-il une meilleure façon de définir ce double numéro, si possible comme une constante?

Était-ce utile?

La solution

float et double littéraux hexadécimaux existent. La syntaxe est 0x1. (Mantisse) p (exposant en décimal) Dans votre cas, la syntaxe serait

double x = 0x1.fffffffffffffp-1

Autres conseils

Il est pas sûr, mais quelque chose comme:

double a;
*(reinterpret_cast<uint64_t *>(&a)) = 0x3FEFFFFFFFFFFFFFL;

Cependant, ce repose sur un boutisme particulier de nombres à virgule flottante sur votre système, donc ne pas le faire!

Au lieu de cela, il suffit de mettre DBL_EPSILON dans <cfloat> (ou sur une autre réponse pointue dans, std::numeric_limits<double>::epsilon()) à bon escient.

#include <iostream>
#include <iomanip>
#include <limits>
using namespace std;

int main()
{
    double const    x   = 1.0 - numeric_limits< double >::epsilon();

    cout
        << setprecision( numeric_limits< double >::digits10 + 1 ) << fixed << x
        << endl;
}

Si vous faites un type entier bit_cast et l'utilisation largeur fixe , il peut être fait en toute sécurité:

template <typename R, typename T>
R bit_cast(const T& pValue)
{
    // static assert R and T are POD types

    // reinterpret_cast is implementation defined,
    // but likely does what you expect
    return reinterpret_cast<const R&>(pValue);
}

const uint64_t target = 0x3FEFFFFFFFFFFFFFL;
double result = bit_cast<double>(target);

Bien que vous pouvez probablement Soustraire epsilon de lui .

Il est un peu archaïque, mais vous pouvez utiliser un union. Si l'on suppose un long long et un double sont les deux 8 octets sur votre système:

typedef union { long long a; double b } my_union;

int main()
{
    my_union c;
    c.b = 1.0;
    c.a--;
    std::cout << "Double value is " << c.b << std::endl;
    std::cout << "Long long value is " << c.a << std::endl;
}

Ici, vous n'avez pas besoin de savoir à l'avance ce que la représentation binaire de 1,0 est.

Cette syntaxe de 0x1.fffffffffffffp-1 est grande, mais seulement dans C99 ou C ++ 17.

Mais il existe une solution, non (pointeur-) coulée, pas UB / IB, juste mathématiques simples.

double x = (double)0x1fffffffffffff / (1LL << 53);

Si je besoin d'un Pi et Pi (double) est 0x1.921fb54442d18p1 en hexadécimal, il suffit d'écrire

const double PI = (double)0x1921fb54442d18 / (1LL << 51);

Si votre constant a grand ou petit exposant, vous pouvez utiliser la fonction exp2 au lieu du changement, mais exp2 est C99 / C ++ 11 ... Utilisez pow pour le sauvetage!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top