valores - Cómo usar la constante PI en C++
la sentencia en c++ const float pi 3.14 hace referencia a (17)
Acabo de encontrar este artículo de Danny Kalev, que tiene un gran consejo para C ++ 14 en adelante.
template<typename T>
constexpr T pi = T(3.1415926535897932385);
Pensé que esto era bastante bueno (aunque usaría el PI de mayor precisión que podía), especialmente porque las plantillas pueden usarlo según el tipo.
template<typename T>
T circular_area(T r) {
return pi<T> * r * r;
}
double darea= circular_area(5.5);//uses pi<double>
float farea= circular_area(5.5f);//uses pi<float>
Quiero usar la constante PI y las funciones trigonométricas en algún programa de C ++. Obtengo las funciones trigonométricas con include <math.h>
. Sin embargo, no parece haber una definición para PI en este archivo de encabezado.
¿Cómo puedo obtener PI sin definirlo manualmente?
C ++ 14 le permite hacer static constexpr auto pi = acos(-1);
C ++ estándar no tiene una constante para PI.
Muchos compiladores de C ++ definen M_PI
en cmath
(o en math.h
para C) como una extensión no estándar. Es posible que tenga que #define _USE_MATH_DEFINES
antes de poder verlo.
Consíguelo de la unidad FPU en chip en su lugar:
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
Dado que la biblioteca estándar oficial no define un PI constante, tendría que definirlo usted mismo. Así que la respuesta a su pregunta "¿Cómo puedo obtener PI sin definirlo manualmente?" es "No, o confías en algunas extensiones específicas del compilador". Si no le preocupa la portabilidad, puede consultar el manual de su compilador para esto.
C ++ te permite escribir
const double PI = std::atan(1.0)*4;
pero no se garantiza que la inicialización de esta constante sea estática. Sin embargo, el compilador G ++ maneja esas funciones matemáticas como intrínsecas y es capaz de calcular esta expresión constante en tiempo de compilación.
De la página man de Posix de math.h :
The <math.h> header shall provide for the following constants. The
values are of type double and are accurate within the precision of the
double type.
M_PI Value of pi
M_PI_2 Value of pi/2
M_PI_4 Value of pi/4
M_1_PI Value of 1/pi
M_2_PI Value of 2/pi
M_2_SQRTPI
Value of 2/ sqrt pi
En Windows (cygwin + g ++), he encontrado que es necesario agregar el indicador -D_XOPEN_SOURCE=500
para que el preprocesador procese la definición de M_PI
en math.h
En algunas plataformas (especialmente las más antiguas) (consulte los comentarios a continuación) es posible que deba
#define _USE_MATH_DEFINES
y luego incluir el archivo de encabezado necesario:
#include <math.h>
y se puede acceder al valor de pi a través de:
M_PI
En mi math.h
(2014) se define como:
# define M_PI 3.14159265358979323846 /* pi */
pero revisa tu math.h
para más Un extracto de "old" math.h
(en 2009):
/* Define _USE_MATH_DEFINES before including math.h to expose these macro
* definitions for common math constants. These are placed under an #ifdef
* since these commonly-defined names are not part of the C/C++ standards.
*/
Sin embargo:
en las plataformas más nuevas (al menos en mi Ubuntu 14.04 de 64 bits) no necesito definir el
_USE_MATH_DEFINES
En las plataformas Linux (recientes) hay valores
long double
también proporcionados como una extensión GNU:# define M_PIl 3.141592653589793238462643383279502884L /* pi */
En lugar de escribir
#define _USE_MATH_DEFINES
Recomendaría usar -D_USE_MATH_DEFINES
o /D_USE_MATH_DEFINES
dependiendo de su compilador.
De esta manera, está seguro de que incluso en el caso de que alguien incluya el encabezado antes de hacerlo (y sin #define) seguirá teniendo las constantes en lugar de un error de compilación que tardará años en rastrear.
Generalmente prefiero definir mi propio: const double PI = 2*acos(0.0);
Porque no todas las implementaciones te lo proporcionan.
La pregunta de si esta función se llama en tiempo de ejecución o está estática en tiempo de compilación no suele ser un problema, porque de todos modos solo ocurre una vez.
Pi puede calcularse como atan(1)*4
. Podrías calcular el valor de esta manera y almacenarlo
Puedes hacerlo:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
Si M_PI
ya está definido en cmath
, esto no hará nada más que incluir cmath
. Si M_PI
no está definido (como es el caso, por ejemplo, en Visual Studio), lo definirá. En ambos casos, puede usar M_PI
para obtener el valor de pi.
Este valor de pi proviene del qmath.h de Qt Creator.
Recomendaría simplemente escribir en pi para la precisión que necesita. Esto no agregaría tiempo de cálculo a su ejecución, y sería portátil sin usar encabezados o #defines. Calcular acos o atan siempre es más costoso que usar un valor precalculado.
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
También puede usar boost, que define constantes matemáticas importantes con la máxima precisión para el tipo solicitado (es decir, flotar frente a doble).
const double pi = boost::math::constants::pi<double>();
Echa un vistazo a la documentación de impulso para más ejemplos.
Uso lo siguiente en uno de mis encabezados comunes en el proyecto que cubre todas las bases:
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif
En una nota al margen, todos los compiladores a continuación definen las constantes M_PI y M_PIl si incluye <cmath>
. No es necesario agregar `#define _USE_MATH_DEFINES que solo es necesario para VC ++.
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
Valores como M_PI, M_PI_2, M_PI_4, etc. no son C ++ estándar, por lo que una solución parece ser una mejor solución. Se pueden formular diferentes expresiones const que calculen la misma pi y me preocupa si (todas) me brindan toda la precisión. El estándar C ++ no menciona explícitamente cómo calcular pi. Por lo tanto, tiendo a volver a definir pi manualmente. Me gustaría compartir la solución a continuación que admite todo tipo de fracciones de pi con total precisión.
#include <ratio>
#include <iostream>
template<typename RATIO>
constexpr double dpipart()
{
long double const pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899863;
return static_cast<double>(pi * RATIO::num / RATIO::den);
}
int main()
{
std::cout << dpipart<std::ratio<-1, 6>>() << std::endl;
}
yo lo haría
template<typename T>
T const pi = std::acos(-T(1));
o
template<typename T>
T const pi = std::arg(-std::log(T(2)));
No escribiría π con la precisión que necesita . ¿Qué se supone que significa eso? La precisión que necesita es la precisión de T
, pero no sabemos nada acerca de T
Podrías decir: ¿De qué estás hablando? T
será float
, double
o long double
. Por lo tanto, simplemente escriba la precisión del long double
, es decir
template<typename T>
T const pi = static_cast<T>(/* long double precision π */);
Pero, ¿sabe realmente que no habrá un nuevo tipo de punto flotante en el estándar en el futuro con una precisión aún mayor que el long double
? Usted no
Y es por eso que la primera solución es hermosa. Puede estar seguro de que el estándar sobrecargará las funciones trigonométricas para un nuevo tipo.
Y, por favor, no diga que la evaluación de una función trigonométrica en la inicialización es una penalización de rendimiento.