définir deux constantes en hexadécimal?
-
08-10-2019 - |
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?
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!