Como usar a constante de PI em C++
quero usar a constante PI e as funções trigonométricas em algum programa C++. Eu tenho as funções trigonométricas com {[[0]}. No entanto, não parece haver uma definição para PI neste arquivo header.
Como posso obter o PI sem o definir manualmente?17 answers
Em algumas plataformas (especialmente mais antigas) (ver os comentários abaixo) poderá ter de
#define _USE_MATH_DEFINES
E depois incluir o ficheiro de cabeçalho necessário:
#include <math.h>
E o valor de pi pode ser acedido através de:
M_PI
No meu math.h
(2014) é definido como:
# define M_PI 3.14159265358979323846 /* pi */
Mas verifique o seu math.h
para mais. Um extracto do " old " math.h
(em 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.
*/
No entanto:
Em plataformas mais recentes (pelo menos no meu Ubuntu 14.04 de 64 bits) eu não preciso definir o
_USE_MATH_DEFINES
-
Em plataformas Linux (recentes) existem também valores
long double
fornecidos como uma extensão GNU:# define M_PIl 3.141592653589793238462643383279502884L /* pi */
O Pi pode ser calculado como atan(1)*4
. Você poderia calcular o valor desta maneira e guardá-lo.
Também pode usar o boost, que define constantes matemáticas importantes com a máxima precisão para o tipo requerido (isto é, float vs double).
const double pi = boost::math::constants::pi<double>();
Verifique a documentaçãopara mais exemplos.
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
Em vez de escrever
#define _USE_MATH_DEFINES
Eu recomendaria a utilização de -D_USE_MATH_DEFINES
ou /D_USE_MATH_DEFINES
dependendo do seu compilador.
Desta forma, ter-lhe-á a certeza de que, mesmo no caso de alguém incluir o cabeçalho antes de o fazer (e sem a definição#), ainda terá as constantes em vez de um erro obscuro do compilador que levará uma eternidade a localizar.
O C++ permite-lhe escrever
const double PI = std::atan(1.0)*4;
Mas a inicialização desta constante não é garantida para ser estática. O compilador G++ however handles those math functions as intrinsics and is able to compute this constant expression at compile-time.
Da página de matemática do Posix man.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
O Padrão C++ não tem uma constante para PI.
Muitos compiladores de c++ definem M_PI
em cmath
(ou em math.h
para C) como uma extensão não-padrão. Você pode ter que #define _USE_MATH_DEFINES
antes que você possa vê-lo.
Eu faria
template<typename T>
T const pi = std::acos(-T(1));
Ou
template<typename T>
T const pi = std::arg(-std::log(T(2)));
Eu não faria escrever em π Com a precisão necessária. O que é que isso quer dizer? A precisão de que você precisa é a precisão de T
, mas não sabemos nada sobre T
.
T
será float
, double
ou long double
. Então, basta digitar a precisão de long double
, i.e.
template<typename T>
T const pi = static_cast<T>(/* long double precision π */);
Mas sabes mesmo que não haverá uma nova tipo de vírgula flutuante na norma no futuro com uma precisão ainda maior do que long double
? Tu não.
E é por isso que a primeira solução é bela. Você pode ter certeza de que o padrão sobrecarregaria as funções trigonométricas para um novo tipo.
E, por favor, não diga que a avaliação de uma função trigonométrica na inicialização é uma penalidade de desempenho.
A questão de saber se esta função é chamada no tempo de execução ou se é estática no tempo de compilação não é normalmente uma questão, porque só acontece uma vez de qualquer maneira.
Uso o seguinte num dos meus cabeçalhos comuns no projecto que cobre todas as 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
Numa nota lateral, todos os compiladores abaixo definem constantes M_PI e M_PIl se incluir <cmath>
. Não há necessidade de adicionar ' # definir _USE_MATH_DEFINES que só é necessário para VC++.
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
Acabei de encontrar este artigo por Danny Kalev que tem uma grande dica para C++14 e up.
template<typename T>
constexpr T pi = T(3.1415926535897932385);
Eu pensei que isso era muito legal( embora eu iria usar o PI de maior precisão que eu poderia), especialmente porque os modelos podem usá-lo com base no 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>
No windows (cygwin + g++), achei necessário adicionar a bandeira {[[0]} para o pré-processador processar a definição de M_PI
em math.h
.
O C++14 permite-lhe fazer static constexpr auto pi = acos(-1);
Podes fazer isto:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
Se M_PI
já estiver definido em cmath
, isto não fará mais nada do que incluir cmath
. Se M_PI
não está definido (o que é o caso, por exemplo, no Visual Studio), ele irá defini-lo. Em ambos os casos, você pode usar M_PI
para obter o valor de pi.
Este valor de pi vem da qmath do Qt Creator.h.
Valores como M_PI, M_PI_2, M_PI_4, etc não são C++ normais, pelo que uma constante parece ser uma solução melhor. Diferentes expressões const podem ser formuladas que calculam o mesmo pi e preocupa-me se elas (todas) me fornecem a precisão completa. A norma C++ não menciona explicitamente como calcular o pi. Portanto, tenho tendência para voltar a definir o pi manualmente. Eu gostaria de compartilhar a solução abaixo que suporta todos os tipos de frações de pi em total precisão.
#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;
}