Há um problema bastante tolo com o número pi em C e C ++. Tanto quanto sei M_PI
definido em math.h
não é exigido por nenhum padrão.
Novos padrões de C ++ introduziram muitas matemáticas complicadas na biblioteca padrão - funções hiperbólicas std::hermite
e std::cyl_bessel_i
, diferentes geradores de números aleatórios e assim por diante.
Algum dos 'novos' padrões trouxe uma constante para pi? Se não - por quê? Como toda essa matemática complicada funciona sem ela?
Estou ciente de perguntas semelhantes sobre pi em C ++ (elas têm vários anos e padrões); Eu gostaria de saber o estado atual do problema.
Também estou muito interessado em saber por que, oh, por que o C ++ ainda não tem uma constante pi, mas tem muito mais matemática complicada.
UPD: Eu sei que posso definir pi-me como 4 * atan (1) ou acos (1) ou pi duplo = 3,14. Certo. Mas por que em 2018 eu ainda tenho que fazer isso? Como as funções matemáticas padrão funcionam sem pi?
UPD2: De acordo com este relatório de viagem para a reunião do Comitê C ++ em julho de 2019 em Colônia, a proposta P0631 (constantes matemáticas) foi aceita no C ++ 20. Parece que finalmente teremos o número pi na biblioteca padrão!
Respostas:
Até e incluindo C ++ 17 pi não é uma constante introduzida na linguagem e é uma dor no pescoço.
Tenho a sorte de usar o boost e eles definem pi com um número suficientemente grande de casas decimais por até 128 bits
long double
.Se você não usar o Boost, codifique-o você mesmo. Defini-lo com uma função trigonométrica é tentador, mas se você fizer isso, não poderá fazê-lo
constexpr
. A precisão das funções trigonométricas também não é garantido por qualquer I Know padrão de ( cf .std::sqrt
), Então realmente você está em terreno perigoso, de facto confiar em tal função.Existe uma maneira de obter um
constexpr
valor para pi usando a metaprogramação: consulte http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/Do C ++ 20, algumas boas notícias. Não é um defininition para pi . O C ++ 20 adiciona algumas constantes matemáticas em
<numbers>
. Por exemplo,std::numbers::pi
é umdouble
tipo.Referência: https://en.cppreference.com/w/cpp/numeric/constants
fonte
constexpr
infelizmente, é por isso que eu digo "Definindo-lo com uma função trig é uma dor"double
(ou algum número ridículo, se você se importa com duplas hipotéticas realmente longas).fsin
instrução de "cerca de 1,37 quintilhão de unidades em último lugar, deixando menos de quatro bits corretos" , e é ainda pior para grandes entradas, nas quais a redução de alcance ocorre várias vezes. Isso é um tanto tangencial às constantes usadaslong double
no C ++, mas, mesmo assim, é puro.Como outros disseram, não há,
std::pi
mas se você quiser umPI
valor preciso, poderá usar:Isso pressupõe que sua implementação C ++ produz um valor arredondado corretamente de PI de
acos(-1.0)
, o que é comum, mas não garantido .Não é
constexpr
, mas na prática otimizar compiladores como gcc e clang avaliá-lo em tempo de compilação. Porém,const
é importante que o otimizador faça um bom trabalho.fonte
acos()
função tem uma inclinação infinita emx = -1
. Conseqüentemente, esse método depende daacos()
implementação para capturar explicitamente basicamente o caso de um-1
argumento preciso e retornar a constante correta diretamente. Melhor usar algo como4*atan(1)
matematicamente muito mais robusto (inclinação bem comportadax = 1
e multiplicação por 4 é sempre preciso com matemática de ponto flutuante).std::acos
em uma expressão constante. clang relata isso como erro. Observe que esta é uma extensão não conforme e, eventualmente, deve ser corrigida no gcc. Consulte esta resposta para obter mais detalhes.Até C ++ 20, não, nenhum dos padrões introduz a constante que representaria o número pi (π). Você pode aproximar o número no seu código:
Outros idiomas, como C #, têm a constante declarada em suas bibliotecas.
Atualização: A partir do C ++ 20, de fato há uma
pi
constante declarada dentro do<numbers>
cabeçalho. Ele é acessado via:std::numbers::pi
.fonte
inline
para o C ++ 17 +.double
. C # é mais fácil, pois odouble
tipo é fixo. Se eu fosse no comitê de padrões C ++ Eu proponho algo comostd::constants<double>::pi
std::numeric_limits<double>::is_iec559;
nesse caso. Confesso que é o que tenho no meu "cabeçalho mestre". Observe que formalmente você precisa verificar todos os tipos de ponto flutuante separadamente. Só porque um é IEEE754 não significa que todos eles são.M_PI
é definido por "um padrão", se não um padrão de idioma : POSIX com a extensão X / Open System Interfaces (que é comumente suportada e necessária para a marca oficial do UNIX).Ainda não está certo o que estará no C ++ 20, mas desde que você perguntou: provavelmente terá essas constantes . O documento foi mesclado na última rodada de recursos do C ++ 20 (para o esboço do comitê em agosto de 2019).
Especificamente, haverá
std::numbers::pi
(do tipodouble
) e um modelo de variável que você pode usar se desejar um tipo de ponto flutuante diferente, por exemplostd::numbers::pi_v<float>
. A lista completa de constantes pode ser vista em [numbers.syn] .fonte
Obviamente, não é uma boa ideia, porque não existe um tipo óbvio com o qual defina pi que seja universalmente aplicável entre domínios.
Pi é, obviamente, um número irracional, portanto não pode ser representado corretamente por nenhum tipo de C ++. Você pode argumentar que a abordagem natural, portanto, é defini-la no maior tipo de ponto flutuante disponível. No entanto, o tamanho do maior tipo de ponto flutuante padrão
long double
não é definido pelo padrão C ++, portanto o valor da constante varia entre os sistemas. Pior ainda, para qualquer programa em que o tipo de trabalho não fosse o maior, a definição de pi seria inadequada, pois imporia um custo de desempenho a cada uso de pi.Também é trivial para qualquer programador encontrar o valor de pi e definir sua própria constante adequada para uso, para que não ofereça nenhuma grande vantagem de incluí-lo nos cabeçalhos de matemática.
fonte
pi
uma constante polimórfica é o caminho claro a seguir - em um idioma com inferência do tipo Hindley-Milner. Em Haskell, sempre tivemospi :: Floating a => a
, para quepi
tivesse automaticamente o valor3.1415927
em umFloat
contexto,3.141592653589793
em umDouble
contexto eπ
em um contexto de computação simbólica. Mas as pessoas realmente gostariam de instanciar explicitamente o parâmetro do modelo? Parece um pouco estranho, especialmente se umalong double
implementação fixa fornecer resultados idênticos na maioria dos aplicativos.auto a = pi<float>;
é completamente bem, certamente mais legível, em seguida, notório4*atan(1)
Editado - Para remover o termo necessário, porque se mostrou controverso. É um termo muito absoluto.
C ++ é uma linguagem grande e complexa; por esse motivo, o Comitê de Padrões inclui apenas coisas que são altamente necessárias . O máximo possível é deixado para bibliotecas padrão que não sejam de idioma ... como o Boost.
boost :: math :: constantes
fonte
std::hermite
estd::cyl_bessel_i
estd::cosh
estd::mersenne_twister_engine
estd::ranlux48
estd::cauchy_distribution
estd::assoc_laguerre
estd::beta
todos eram absolutamente necessários, todos nós os usamos todos os dias!