2012-08-30 32 views
17

Actualmente estoy trabajando en un proyecto de C++ que realiza cálculos numéricos. La gran mayoría del código usa valores de punto flotante de precisión simple y funciona perfectamente bien con eso. Debido a esto, utilizo indicadores de compilación para hacer que los literales de coma flotante básicos tengan una precisión única en lugar de la precisión doble, que es la predeterminada. Encuentro que esto hace que las expresiones sean más fáciles de leer y no tengo que preocuparme de olvidar una 'f' en alguna parte. Sin embargo, de vez en cuando necesito la precisión adicional que ofrecen los cálculos de precisión doble y mi pregunta es cómo puedo obtener un literal de precisión doble en esa expresión. De todas las maneras que he intentado hasta ahora, primero almaceno el valor en una sola variable de precisión y convierte el valor truncado a un valor de precisión doble. No es lo que quiero¿Hay un sufijo literal en punto flotante en C++ para hacer un número doble de precisión?

Algunas formas que he probado hasta ahora se dan a continuación.

#include <iostream> 

int main() 
{ 
    std::cout << sizeof(1.0E200) << std::endl; 
    std::cout << 1.0E200 << std::endl; 

    std::cout << sizeof(1.0E200L) << std::endl; 
    std::cout << 1.0E200L << std::endl; 

    std::cout << sizeof(double(1.0E200)) << std::endl; 
    std::cout << double(1.0E200) << std::endl; 

    std::cout << sizeof(static_cast<double>(1.0E200)) << std::endl; 
    std::cout << static_cast<double>(1.0E200) << std::endl; 

    return 0; 
} 

Una ejecución con constantes de precisión únicas arroja los siguientes resultados.

~/path$ g++ test.cpp -fsingle-precision-constant && ./a.out 
test.cpp:6:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:7:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:12:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:13:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:15:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:16:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
4 
inf 
16 
1e+200 
8 
inf 
8 
inf 

Es mi entendimiento de que los 8 bytes proporcionados por los dos últimos casos, debería ser suficiente para mantener 1.0E200, una teoría apoyada por la siguiente salida, en el que el mismo programa se compila sin -fsingle precisión constante .

~/path$ g++ test.cpp && ./a.out 
8 
1e+200 
16 
1e+200 
8 
1e+200 
8 
1e+200 

Una posible solución sugerida por los ejemplos anteriores es el uso de precisión cuádruple literales de punto en todas partes que originalmente la intención de utilizar doble precisión, y el reparto de doble precisión cuando así lo requiera tales bibliotecas y flotante. Sin embargo, esto se siente un poco derrochador.

¿Qué más puedo hacer?

+0

no probado, pero 'strtod ("1e + 200") 'simplemente podría optimizarse para la constante de punto flotante de doble precisión que desee. –

+4

No sé, esto suena un poco como si estuvieras creando un problema para ti. ¿Por qué no dejarlo tal como está y anexar 'f' a todo lo que no necesite doble precisión? – Mysticial

+1

Puede poner sus constantes dobles en un archivo separado y compilar sin el indicador '-single-precision-constant'. –

Respuesta

19

Como dijo Mark, el estándar dice que es un doble a menos que sea seguido de una f.

Existen buenas razones detrás del estándar y el uso de indicadores del compilador para evitarlo es una mala práctica.

Por lo tanto, el enfoque correcto sería:

  1. quitar la bandera compilador
  2. Fijar todas las advertencias acerca de la pérdida de precisión cuando se almacenan los valores dobles en las variables de punto flotante (añadir en todos los sufijos f)
  3. Cuando necesite el doble, omita el sufijo f.

Probablemente no sea la respuesta que estaba buscando, pero es el enfoque que debe usar si le preocupa la longevidad de su código base.

+0

¿Cuáles son esas "buenas razones" exactamente? Se parece más a una limitación que hace que esa bandera en particular sea difícil de usar. Además, ¿qué hay de malo con el uso de 'double (1.0E200L)'? ¿Cómo afecta eso la longevidad? –

+0

Una base de código no debe limitarse a un compilador específico. Un compilador debe cumplir con un estándar. Un estándar debe ser la única fuente de verdad. Afecta la longevidad porque no cumplir con la norma introduce incoherencias a lo largo del tiempo, ya que varios programadores trabajan en la base de códigos y cada uno hace las cosas de la manera que prefiera. Esta es la razón por la que existen los estándares. – Carl

11

Si lee 2.13.3/1 verá:

El tipo de un literal flotante es el doble menos que se especifique de forma explícita por un sufijo. Los sufijos f y F especifican float, los sufijos l y L especifican long double.

En otras palabras, no hay sufijo para especificar double para un literal de coma flotante constante si cambia el valor predeterminado a float. Desafortunadamente no puedes tener lo mejor de ambos mundos en este caso.

+1

-1, 'double (1.0E200L)' funciona bien. – orlp

+0

No importa, el autor de la pregunta propuso esto en la pregunta y lo encontró "inútil". – orlp

5

No se puede definir su propio sufijo, pero tal vez una macro como

#define D(x) (double(x##L)) 

iba a funcionar para usted. El compilador debería simplemente emitir una doble constante, y aparece con -O2 en mi sistema.

+0

+1 solo para comprobar que el compilador emite una constante doble, lo cual era demasiado vago cuando comento la pregunta para decir que :-) –

8

Si se lo puede permitir GCC 4.7 o Clang 3.1, utilizar un literal definido por el usuario:

double operator "" _d(long double v) { return v; } 

Uso:

std::cout << sizeof(1.0E200_d) << std::endl; 
std::cout << 1.0E200_d << std::endl; 

Resultado:

8 
1e+200 
Cuestiones relacionadas