C ++ 11, 14, 17 ou 20 introduz uma constante padrão para pi?


170

Há um problema bastante tolo com o número pi em C e C ++. Tanto quanto sei M_PIdefinido em math.hnã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::hermitee 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!


Você nota a existência de perguntas antigas, como a melhor plataforma independente pi constante? . Se você se preocupa que eles estejam desatualizados, sempre é possível definir uma recompensa em um deles pedindo respostas com base no C ++ 17 etc ... Então todas as respostas estariam em um só lugar. Por que ainda é uma boa pergunta, mas talvez isso deva se concentrar no porquê e solicitar atualizações deve ser uma recompensa pelas perguntas existentes.
— Shafik Yaghmour 13/04/19

Eu acho que pode pena acrescentar novas respostas desde C ++ 20 adicionada uma constante pi, tanto quanto eu sei
— Guillaume Racicot

@GuillaumeRacicot i atualizou a pergunta. Não tenho certeza se devemos abordar o C ++ 20, pois ainda não está oficialmente lançado.
— Amomum

@GuillaumeRacicot: É um pouco tarde para adicionar uma…
— Davis Herring

Respostas:


101

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 constexprvalor 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é um doubletipo.

Referência: https://en.cppreference.com/w/cpp/numeric/constants


9
@Lundin: Mas isso não pode ser um constexprinfelizmente, é por isso que eu digo "Definindo-lo com uma função trig é uma dor"
— Bate-Seba

9
Por que isso Importa? Pi é uma constante, não está sujeita a alterações ou a qualquer implementação específica. Escreva o valor (em um objeto const, se quiser) para o número de lugares significativos double(ou algum número ridículo, se você se importa com duplas hipotéticas realmente longas).
— R .. GitHub Pare de ajudar o gelo

10
@ R..O problema que tenho com isso é o que parece ridículo agora pode se tornar perfeitamente saudável daqui a 20 anos. (640k de Bill Gates vem à mente). Confio no Boost para acompanhar a evolução da arquitetura.
— Bate-Seba


10
@KonradRudolph: Um pi de alta precisão é importante se estiver implementando uma redução de alcance. Por exemplo, a constante Pi interna do x86 / x87 (mantissa total de 64 bits) leva a um erro de pior caso para pequenas entradas à fsininstruçã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 usadas long doubleno C ++, mas, mesmo assim, é puro.
— Peter Cordes

31

Como outros disseram, não há, std::pimas se você quiser um PIvalor preciso, poderá usar:

constexpr double pi = std::acos(-1);

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.


2
Isso é perigoso porque a acos()função tem uma inclinação infinita em x = -1. Conseqüentemente, esse método depende da acos()implementação para capturar explicitamente basicamente o caso de um -1argumento preciso e retornar a constante correta diretamente. Melhor usar algo como 4*atan(1)matematicamente muito mais robusto (inclinação bem comportada x = 1e multiplicação por 4 é sempre preciso com matemática de ponto flutuante).
— cmaster - restabelece monica 5/08/19

1
Não temos permissão para usar std::acosem 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.
— badola 12/09/19

31

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:

constexpr double pi = 3.14159265358979323846;

Outros idiomas, como C #, têm a constante declarada em suas bibliotecas.

Atualização: A partir do C ++ 20, de fato há uma piconstante declarada dentro do <numbers>cabeçalho. Ele é acessado via: std::numbers::pi.


6
Convém adicionar inlinepara o C ++ 17 +.
— Deduplicator

8
Ta. Tenha um voto positivo, mas observe que sua definição ainda está vulnerável à imprecisão com plataformas com diferentes definições de double. C # é mais fácil, pois o doubletipo é fixo. Se eu fosse no comitê de padrões C ++ Eu proponho algo comostd::constants<double>::pi
— Bate-Seba

11
@Duplicator não é constexpr implicitamente embutido também ...?
— whn

4
@R. É justo, embora você deva afirmar estática 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.
— Bate-Seba

2
@DanielSchepler Então, qual é esse "número"? Eu não sabia que existem números duplos com 16 bases.
— BЈовић

29

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 tipo double) e um modelo de variável que você pode usar se desejar um tipo de ponto flutuante diferente, por exemplo std::numbers::pi_v<float>. A lista completa de constantes pode ser vista em [numbers.syn] .


Sinta-se à vontade para reformular minha edição como achar melhor - eu só queria adicionar a ortografia real das novas constantes aqui para posteridade.
— Barry

12

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 doublenã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.


10
O C ++ 14 nos deu modelos variáveis. Não é para isso que eles servem?
— Amomum

21
falado como um verdadeiro membro do comitê, fale sobre todas as maneiras pelas quais isso não pode ser feito, apesar de apresentar um caminho claro a seguir. Veja os exemplos de variáveis ​​surpreendentemente relevantes . Não acho que sua resposta seja ruim, mas tenho certeza de que não ajudaria a eterna depressão de Bjarne Stroustrup ao arrependimento de entregar o controle do futuro do C ++ a um comitê muito indeciso.
— whn

4
@snb Concordo que fazer piuma constante polimórfica é o caminho claro a seguir - em um idioma com inferência do tipo Hindley-Milner. Em Haskell, sempre tivemos pi :: Floating a => a, para que pitivesse automaticamente o valor3.1415927 em um Floatcontexto, 3.141592653589793em um Doublecontexto 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 uma long doubleimplementação fixa fornecer resultados idênticos na maioria dos aplicativos.
— usar o seguinte comando

2
@leftaroundabout Eu acredito que a escrita auto a = pi<float>;é completamente bem, certamente mais legível, em seguida, notório4*atan(1)
— Amomum

1
Ugh, eu diminuí o voto com um clique errado e agora não posso desfazê-lo. Desculpe. Isso merece um +1 para uma boa explicação do raciocínio do comitê, por que ele não foi adicionado, mesmo que eu pessoalmente ache que o raciocínio é fundamentalmente defeituoso pelas razões pelas quais as pessoas já apontaram.
— Fund Monica's Lawsuit

-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


29
Claro, std::hermiteestd::cyl_bessel_i e std::coshe std::mersenne_twister_enginee std::ranlux48e std::cauchy_distributione std::assoc_laguerree std::betatodos eram absolutamente necessários, todos nós os usamos todos os dias!
— Amomum

2
Tenho certeza de que você não conseguiu nem mesmo o próprio comitê aprovar a idéia de que tudo em que votam é "absolutamente necessário". Não se trata de necessidade, mas de agregar valor ao idioma - quase nada na biblioteca padrão é necessário para escrever programas e, nesse caso, a maior parte do idioma principal também pode ser descartada (se você não se importa de trabalhar em um Tarpit de Turing, isto é). O valor da inclusão de uma constante para pi pode ser debatido, mas a idéia de que ela não está lá porque não é necessária não retém água.
— Jeroen Mostert

Não reclame comigo, estou apenas citando o comitê de padrões. Houve longas discussões abertas sobre quanto do impulso deveria ser incluído no padrão C ++ 11. A razão pela qual um subconjunto tão pequeno foi criado é porque os escritores do compilador reclamaram da quantidade de testes envolvidos. Portanto, se algo está dentro dos padrões, está lá porque alguém achou necessário padronizá-lo. Só porque você não sabe o porquê, não significa que não havia razão.
— Tiger4Hire

1
@ Tiger4Hire Tenho certeza de que há motivos para tudo, simplesmente não consigo entender por que a constante para pi não foi adicionada quando muitas coisas mais complexas eram. É fácil escrever Constant com modelos de variáveis ​​e não exigirá muitos testes dos escritores do compilador.
— Amomum

@ Amomum: Sim, adicionar pi parece uma pequena sobrecarga para uma grande vitória. Pessoalmente, eu preferiria ver std :: network antes de std :: math :: constantes.
— Tiger4Hire
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.