2010-10-16 16 views
6

Me gustaría tener el número más cercano por debajo de 1.0 como punto flotante. Al leer el artículo de wikipedia en IEEE-745, he logrado averiguar que la representación binaria para 1.0 es 3FF0000000000000, por lo que el valor doble más cercano es en realidad 0x3FEFFFFFFFFFFFFF.define constante doble como hexadecimal?

La única manera que conozco para inicializar un doble con estos datos binarios es la siguiente:

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

que es bastante complicado de usar.

¿Hay alguna manera mejor de definir este número doble, si es posible como una constante?

+0

¿Puedo preguntar por qué es necesario esto? –

+0

la única manera es esta ... a menos que su implementación en C++ tenga 64 bits de soporte entero. –

+0

Esto es simplemente quisquilloso, pero es IEEE-754-1985 (no IEEE-745). – George

Respuesta

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

No es seguro, pero algo como:

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

Sin embargo, esto se basa en un orden de bits particular de números de punto flotante en el sistema, así que no hagas esto!

En su lugar, simplemente ponga DBL_EPSILON en <cfloat> (o como se señala en otra respuesta, std::numeric_limits<double>::epsilon()) para un buen uso.

+0

Tratarlo como un entero debe hacerlo independiente de Endian (a menos que tenga uno de esos sistemas "mixtos") –

+0

@Rick Regan: ¿Quién puede decir que la "endianidad" de la representación de su plataforma de tipos de punto flotante es consistente con la representación de tipos enteros? –

+0

Teóricamente tienes razón, pero ¿tienes un ejemplo (además de los "flotadores suaves" endianados mixtos)? –

1

Si comete un bit_cast y utilizar fixed-width integer types, se puede hacer de manera segura:

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

Aunque probablemente puede subtract epsilon from it.

+0

No estoy seguro de por qué se tomó la molestia de definir bit_cast cuando podría haber usado 'reinterpret_cast ' directamente. Todavía parece una buena solución. –

+0

@Mark: Eso no afirmaría estáticamente que ambos tipos sean tipos de POD, y haría más fácil romper las reglas de aliasing. (Es cierto que di una solución más general que la requerida, en este caso simplemente hacerlo directamente funciona bien.) – GManNickG

0

Es un poco arcaico, pero puede usar un union. Suponiendo una long long y una double son ambos longitud de 8 bytes en su sistema:

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

Aquí no se necesita saber de antemano lo que la representación de bits de 1,0 es.

+1

Eso conduce a UB, estrictamente hablando. – GManNickG

5

Flotador hexadecimal y literales dobles existen. La sintaxis es 0x1. (Mantisa) p (exponente en decimal) En su caso, la sintaxis sería

double x = 0x1.fffffffffffffp-1 
+0

Nunca antes había escuchado sobre esta sintaxis. Tiene una referencia? –

+0

Creo que es parte del estándar C99. Funciona con compiladores de GNU, no con otros. – Shum

+0

@Mark Ransom: escribí un artículo sobre esto recientemente: http://www.exploringbinary.com/hexadecimal-floating-point-constants/ –

Cuestiones relacionadas