Use el argumento de la plantilla de entero para crear el doble de compiletime -- ++ camp Relacionados El problema

Use integer template argument to create compiletime double


6
vote

problema

Español

Es posible crear un doble que sostiene el valor de 1 * 10 ^ x donde X se basa en un parámetro de plantilla de entero. Así que algo como:

  template < int exp > struct DoubleValue {     static constexpr double value = ????; }  double d = DoubleValue<20>::value; // = 1e20 double d = DoubleValue<-20>::value; // = 1e-20   

Como se puede crear con literas, parece que algo así debería ser posible.

Me gustaría que se evalúe el valor en el tiempo de compilación (por lo que STD :: Pow no funcionará hasta lo que yo sepa). Además, si es posible, me gustaría poder evitar cálculos iterativos reales ((tal vez infundados) miedo a los problemas de precisión). También me gustaría poder usar valores más grandes como exponentes, como por ejemplo 200, lo que hace que sea imposible almacenar el valor en un tipo de entero estándar.

Original en ingles

Is it possible to create a double which holds the value of 1*10^x where x is based on a integer template parameter. So something like:

template < int exp > struct DoubleValue {     static constexpr double value = ????; }  double d = DoubleValue<20>::value; // = 1e20 double d = DoubleValue<-20>::value; // = 1e-20 

As it can be created with litterals, it seems that something like this should be possible.

I would like the value to be evaluated at compile time (so std::pow will not work as far as I know). Also, if possible, I would like to be able to avoid actual iterative computations ((maybe unfounded) fear for precision problems). I would also like to be able to use larger values as exponent, like for example 200, which makes it impossible to store the value in a standerd integer type.

  
       
       

Lista de respuestas

6
 
vote
vote
La mejor respuesta
 

Suponiendo que su compilador admite C ++ 14 o superior (que debe ser un supuesto válido en el año 2019) Esto es muy simple utilizando una función constexpr :

  constexpr double myPow(double x, int exp) {     double pow = 1.0;     for (int i = 0; i < exp; ++i)         pow *= x;     for (int i = 0; i > exp; --i)         pow /= x;     return pow; }  template < int exp > struct DoubleValue {     static constexpr double value = myPow(10.0, exp); };   

Consulte aquí para verificar que funciona y que incluso sin optimización se genera el valor en el tiempo de compilación .

Dependiendo de su caso de uso, es posible que ni siquiera necesite la estructura #include <iostream> template <int e> struct DoubleValue { static constexpr double value = 10.0 * DoubleValue<e - 1>::value; }; template <> struct DoubleValue<0> { static constexpr double value = 1.0; }; int main() { std::cout << DoubleValue<20>::value << ' '; //1e+20 } 2 , pero puede usar directamente myPow() .


Actualización

Como señaló @BOB__ en los comentarios, puede haber mejores algoritmos con respecto a la precisión numérica que la presentada aquí. Pero desde C ++ 14 muchas características básicas de idioma se pueden usar en El cuerpo de una función constexpr . Entonces, siempre y cuando no necesite ninguna biblioteca externa, usted es libre de implementar cualquier algoritmo que se adapte a sus necesidades.

 

Assuming that your compiler supports C++14 or higher (which should be a valid assumption in the year 2019) this is very simple using a constexpr function:

constexpr double myPow(double x, int exp) {     double pow = 1.0;     for (int i = 0; i < exp; ++i)         pow *= x;     for (int i = 0; i > exp; --i)         pow /= x;     return pow; }  template < int exp > struct DoubleValue {     static constexpr double value = myPow(10.0, exp); }; 

See here to verify that it works and that even without optimization the value is generated at compile time.

Depending on your use case you might not even need the DoubleValue struct but can directly use myPow().


Update

As pointed out by @Bob__ in the comments, there may be better algorithms regarding numerical precision than the one presented here. But since C++14 many basic language features can be used in the body of a constexpr function. So, as long as you don't need any external library for it, you are free to implement whatever algorithm fits your needs.

 
 
     
     
1
 
vote

Si lo desea en el tiempo de compilación sin std::pow , esto debería hacerlo:

  #include <iostream>  template <int e> struct DoubleValue {     static constexpr double value = 10.0 * DoubleValue<e - 1>::value; }; template <> struct DoubleValue<0> {     static constexpr double value = 1.0; }; int main() {     std::cout << DoubleValue<20>::value << ' '; //1e+20 }   

Fiddle de C ++

 

If you want it at compile time without std::pow, this should do it:

#include <iostream>  template <int e> struct DoubleValue {     static constexpr double value = 10.0 * DoubleValue<e - 1>::value; }; template <> struct DoubleValue<0> {     static constexpr double value = 1.0; }; int main() {     std::cout << DoubleValue<20>::value << '\n'; //1e+20 } 

C++ Fiddle

 
 
       
       
0
 
vote

Dado que necesita el valor disponible en el tiempo de compilación, casi la única manera de resolverlo, que vino a mi mente son plantillas recursivas. Sin embargo, el hecho, que necesita para dicha plantilla para hacer diferentes cosas, según el firme de la valor aprobada, complica las cosas. Lo primero que vendría a la mente, sería escribir una plantilla tan recursiva:

  template <int exp> struct DoubleValue     {     static constexpr double value = (exp < 0                                      ? DoubleValue<exp+1>::value / 10                                      : 10 * DoubleValue<exp-1>::value);     };  // Default case template <> struct DoubleValue<0>     {     static constexpr double value = 1;     };   

Sin embargo, tal solución no funcionaría, debido al hecho de que ambas ramas de la expresión ternaria, tendrían que ser resueltas, y eso siempre lo llevaría a la recursión infinita, ya que una de las ramas no lo haría t tiende a 0. Entonces, Sfinae vino a la mente:

  // Base case. template <int exp, class Enable = void> struct DoubleValue     {     };  // Case when exp is positive template <int exp> struct DoubleValue<exp, typename std::enable_if<(exp > 0)>::type>     {     static constexpr double value = 10 * DoubleValue<exp-1>::value;     };  // Case when exp is negative template <int exp> struct DoubleValue<exp, typename std::enable_if<(exp < 0)>::type>     {     static constexpr double value = DoubleValue<exp+1>::value / 10;     };  // Default case. template <> struct DoubleValue<0>     {     static constexpr double value = 1;     };   

Demo en vivo .

 

Since you need the value to available in compile time, pretty much the only way to solve it, that came to my mind is recursive templates. However, the fact, that you need for said template to do different things, based on the signedness of the passed value, complicates things. First thing that would come to mind, would be to write such a recursive template:

template <int exp> struct DoubleValue     {     static constexpr double value = (exp < 0                                      ? DoubleValue<exp+1>::value / 10                                      : 10 * DoubleValue<exp-1>::value);     };  // Default case template <> struct DoubleValue<0>     {     static constexpr double value = 1;     }; 

However, such solution wouldn't work, due to the fact, that both branches of the ternary expression, would need to be resolved, and that would, always, lead to the infinite recursion, since one of the branches wouldn't tend to 0. Then, SFINAE came to mind:

// Base case. template <int exp, class Enable = void> struct DoubleValue     {     };  // Case when exp is positive template <int exp> struct DoubleValue<exp, typename std::enable_if<(exp > 0)>::type>     {     static constexpr double value = 10 * DoubleValue<exp-1>::value;     };  // Case when exp is negative template <int exp> struct DoubleValue<exp, typename std::enable_if<(exp < 0)>::type>     {     static constexpr double value = DoubleValue<exp+1>::value / 10;     };  // Default case. template <> struct DoubleValue<0>     {     static constexpr double value = 1;     }; 

Live Demo.

 
 
   
   

Relacionados problema

64  Montón de corrupción bajo Win32; ¿Cómo localizar?  ( Heap corruption under win32 how to locate ) 
Estoy trabajando en una aplicación de MultiShreaded que está corrompiendo el montón. Las herramientas habituales para localizar esta corrupción parecen ser ...

30  ¿Soporte de expresión regular fácil de usar en C ++? [cerrado]  ( Easy to use regular expression support in c ) 
cerrado. Esta pregunta no cumple con pautas de desbordamiento de pila . Actualmente no está aceptando respuestas. ...

164  Cómo usar la API de C Socket en C ++ en Z / OS  ( How to use the c socket api in c on z os ) 
Tengo problemas para que la API de los sockets de C funcione correctamente en C ++ en Z / OS. Aunque estoy incluyendo sys/socket.h , Sigo obtengo los error...

42  Generación de números aleatorios robustos [cerrado]  ( Robust random number generation ) 
Según lo que actualmente representa, esta pregunta no es un buen ajuste para nuestro Q & Amp; un formato. Esperamos que las...

30  Asegurar que las excepciones siempre sean atrapadas  ( Ensuring that exceptions are always caught ) 
Las excepciones en C ++ no deben ser atrapadas (sin errores de tiempo de compilación) por la función de llamada. Así que depende del juicio del desarrollador,...

27  ¿Comunicación de cliente-cliente de múltiples direcciones asíncrona en el mismo socket abierto?  ( Asynchronous multi direction server client communication over the same open sock ) 
Tengo una aplicación cliente-servidor donde el cliente está en un dispositivo Windows Mobile 6, escrito en C ++ y el servidor está en Windows completo y escri...

19  ¿Qué herramienta de integración continua es la mejor para un proyecto C ++? [cerrado]  ( What continuous integration tool is best for a c project ) 
cerrado . Esta pregunta es basada en opinión . Actualmente no está aceptando respuestas. Cerrado ha...

35  Berkeleydb concurrencia  ( Berkeleydb concurrency ) 
¿Cuál es el nivel óptimo de concurrencia de que la implementación de C ++ de BerkeleyDB puede apoyar razonablemente? ¿Cuántos hilos puedo haber golpeado la...

56  ¿Debo usar clases anidadas en este caso?  ( Should i use nested classes in this case ) 
Estoy trabajando en una colección de clases utilizadas para la reproducción de video y la grabación. Tengo una clase principal que actúa como la interfaz públ...

22  ¿Construir para Windows NT 4.0 usando Visual Studio 2005?  ( Build for windows nt 4 0 using visual studio 2005 ) 
Una aplicación de MFC que estoy tratando de migrar usos afxext.h , que causa 9988777664 para configurar, lo que causa este error si configuro /MT5 : Ut...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos