C ++ 11, 14, 17 ou 20 introduit-il une constante standard pour pi?

170

Il y a un problème plutôt idiot avec le nombre pi en C et C ++. Autant que je sache, M_PIdéfini dans math.hn'est requis par aucune norme.

Les nouvelles normes C ++ ont introduit beaucoup de mathématiques compliquées dans la bibliothèque standard - des fonctions hyperboliques std::hermiteet std::cyl_bessel_idifférents générateurs de nombres aléatoires, etc.

L'une des «nouvelles» normes a-t-elle introduit une constante pour pi? Sinon, pourquoi? Comment tout ce calcul compliqué fonctionne-t-il sans cela?

J'ai connaissance de questions similaires sur pi en C ++ (elles datent de plusieurs années et ont des standards); J'aimerais connaître l'état actuel du problème.

Je suis également très intéressé par pourquoi oh pourquoi C ++ n'a toujours pas de constante pi mais a beaucoup de mathématiques plus compliquées.

UPD: Je sais que je peux définir pi moi-même comme 4 * atan (1) ou acos (1) ou double pi = 3,14. Sûr. Mais pourquoi dois-je encore le faire en 2018? Comment les fonctions mathématiques standard fonctionnent-elles sans pi?

UPD2: Selon ce rapport de voyage pour la réunion du comité C ++ en juillet 2019 à Cologne, la proposition P0631 (constantes mathématiques) a été acceptée dans C ++ 20. Il semble donc que nous aurons enfin le numéro pi dans la bibliothèque standard!

Amomum
la source
Vous notez l'existence d'anciennes questions telles que la constante pi indépendante de la meilleure plateforme? . Si vous craignez qu'ils ne soient pas à jour, vous pouvez toujours mettre une prime sur l'un d'entre eux demandant des réponses basées sur C ++ 17 etc ... Alors toutes les réponses seraient au même endroit. Pourquoi est toujours une bonne question, mais peut-être que cela devrait se concentrer sur le pourquoi et demander des mises à jour devrait être une prime sur les questions existantes.
Shafik Yaghmour
Je pense que cela vaut la peine d'ajouter de nouvelles réponses puisque C ++ 20 a ajouté une constante pi pour autant que je sache
Guillaume Racicot
@GuillaumeRacicot j'ai mis à jour la question. Je ne sais pas si nous devrions aborder C ++ 20 car il n'est pas encore officiellement sorti.
Amomum
@GuillaumeRacicot: Il est un peu tard pour en ajouter un…
Davis Herring

Réponses:

101

Jusqu'au C ++ 17 inclus, pi n'est pas une constante introduite dans le langage, et c'est une douleur dans le cou.

J'ai la chance d'utiliser boost et ils définissent pi avec un nombre suffisamment grand de décimales pour même un 128 bits long double.

Si vous n'utilisez pas Boost, codez-le vous-même. Le définir avec une fonction trigonométrique est tentant, mais si vous faites cela, vous ne pouvez pas en faire un constexpr. La précision des fonctions trigonométriques est également garanti par aucun savoir standard I ( cf . std::sqrt), Donc vraiment vous êtes sur un terrain dangereux reposant en effet sur une telle fonction.

Il existe un moyen d'obtenir une constexprvaleur pour pi en utilisant la métaprogrammation: voir http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


De C ++ 20, quelques bonnes nouvelles. Il existe une définition pour pi . C ++ 20 ajoute des constantes mathématiques dans <numbers>. Par exemple std::numbers::piest un doubletype.

Référence: https://en.cppreference.com/w/cpp/numeric/constants

Bathsheba
la source
9
@Lundin: Mais cela ne peut pas être constexprmalheureusement, c'est pourquoi je dis "Le définir avec une fonction trigonométrique est pénible"
Bathsheba
9
Pourquoi est-ce important? Pi est une constante, non sujette à changement ou à quelque chose de spécifique à l'implémentation. Écrivez simplement la valeur (dans un objet const si vous le souhaitez) au nombre de places significatives pour double(ou à un nombre ridicule si vous vous souciez des doubles hypothétiques très longs).
R .. GitHub STOP HELPING ICE
10
@ R..Le problème que j'ai avec cela est que ce qui semble ridicule maintenant peut devenir parfaitement sain d'esprit dans 20 ans environ. (Les 640k de Bill Gates me viennent à l'esprit). Je fais confiance à Boost pour suivre l'évolution de l'architecture.
Bathsheba
10
@KonradRudolph: Un pi de haute précision est important lors de la mise en œuvre de la réduction de portée. Par exemple, la constante Pi interne de x86 / x87 (mantisse 64 bits complète) conduit à une erreur dans le pire des cas pour les petites entrées à l' fsininstruction "d'environ 1,37 quintillion d'unités à la dernière place, laissant moins de quatre bits corrects" , et c'est pire encore pour les entrées volumineuses où la réduction de la portée s’enroule plusieurs fois. C'est quelque peu tangentiel aux constantes utilisées pour long doubleen C ++, mais parfait quand même.
Peter Cordes
31

Comme d'autres l'ont dit, il n'y en a pas, std::pimais si vous voulez une PIvaleur précise , vous pouvez utiliser:

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

Cela suppose que votre implémentation C ++ produit une valeur correctement arrondie de PI from acos(-1.0), ce qui est courant mais non garanti .

Ce n'est pas le cas constexpr, mais en pratique, l'optimisation des compilateurs comme gcc et clang l'évalue au moment de la compilation. Cependant, il constest important que l'optimiseur fasse du bon travail.

0x476f72616e
la source
2
Ceci est dangereux car la acos()fonction a une pente infinie à x = -1. Par conséquent, cette méthode repose sur l' acos()implémentation pour intercepter explicitement le cas d'un -1argument précis et renvoyer directement la constante correcte. Mieux vaut utiliser quelque chose comme 4*atan(1)qui est mathématiquement beaucoup plus robuste (une pente à x = 1et une multiplication par 4 sont toujours précises avec des mathématiques en virgule flottante).
cmaster - réintégrer monica
1
Nous ne sommes pas autorisés à utiliser std::acosdans une expression constante. clang signale cela comme une erreur. Veuillez noter qu'il s'agit d'une extension non conforme et qu'elle devrait éventuellement être corrigée dans gcc. Veuillez vous référer à cette réponse pour plus de détails.
badola le
31

Jusqu'en C ++ 20, non, aucune des normes n'introduit la constante qui représenterait le nombre pi (π). Vous pouvez approximer le nombre dans votre code:

constexpr double pi = 3.14159265358979323846;

D'autres langages tels que C # ont la constante déclarée dans leurs bibliothèques.

Mise à jour: A partir du C ++ 20, il y a en effet une piconstante déclarée à l'intérieur de l'en- <numbers>tête. Il est accessible via: std::numbers::pi.

Ron
la source
6
Vous voudrez peut-être ajouter inlinepour C ++ 17 +.
Deduplicator
8
Ta. Ayez un vote favorable, mais notez que votre définition est toujours vulnérable à l'imprécision avec des plates-formes avec des définitions différentes de double. C # est facile puisque le doubletype est fixe. Si j'étais membre du comité des normes C ++, je proposerais quelque chose commestd::constants<double>::pi
Bathsheba
11
@Deduplicator n'est pas également implicitement en ligne constexpr ...?
whn le
4
@R. Assez juste, bien que vous devriez vous affirmer statique std::numeric_limits<double>::is_iec559;dans ce cas. Ce qui, je l'avoue, est ce que j'ai dans mon "master header". Notez que formellement, vous devez vérifier tous les types à virgule flottante séparément. Ce n'est pas parce que l'un est IEEE754 qu'ils le sont tous.
Bathsheba
2
@DanielSchepler Alors, quel est ce "nombre" censé être? Je ne savais pas qu'il y avait des nombres doubles avec 16 base.
BЈовић
29

M_PIest défini par "un standard", sinon un standard de langage : POSIX avec l'extension X / Open System Interfaces (qui est très couramment supportée et requise pour la marque UNIX officielle).

On ne sait pas (toujours) ce que sera en C ++ 20, mais puisque vous l'avez demandé: il aura probablement de telles constantes . Le document a été fusionné lors de la dernière série de fonctionnalités C ++ 20 (pour le projet de comité en août 2019).

Plus précisément, il y aura à la fois std::numbers::pi(de type double) et un modèle de variable que vous pouvez utiliser si vous voulez un type à virgule flottante différent, par exemple std::numbers::pi_v<float>. La liste complète des constantes peut être vue dans [numbers.syn] .

Davis Herring
la source
N'hésitez pas à reformuler ma modification comme bon vous semble - je voulais juste ajouter l'orthographe réelle des nouvelles constantes ici pour la postérité.
Barry
12

Ce n'est évidemment pas une bonne idée car il n'y a pas de type évident avec lequel définir pi qui soit universellement applicable à travers les domaines.

Pi est, bien sûr, un nombre irrationnel, donc il ne peut être correctement représenté par aucun type C ++. Vous pourriez dire que l'approche naturelle consiste donc à le définir dans le plus grand type à virgule flottante disponible. Cependant, la taille du plus grand type à virgule flottante standard long doublen'est pas définie par la norme C ++, de sorte que la valeur de la constante varie d'un système à l'autre. Pire encore, pour tout programme dans lequel le type de travail n'était pas ce type le plus grand, la définition de pi serait inappropriée car elle imposerait un coût de performance à chaque utilisation de pi.

Il est également trivial pour tout programmeur de trouver la valeur de pi et de définir sa propre constante utilisable, donc cela ne fournit pas un grand avantage de l'inclure dans les en-têtes mathématiques.

Jack Aidley
la source
10
C ++ 14 nous a donné des modèles de variables. N'est-ce pas pour ça qu'ils sont?
Amomum
21
parlé comme un vrai membre du comité, parlez de toutes les façons dont cela ne peut pas être fait malgré la présentation d'une voie à suivre claire. Voir les exemples de modèles de variables étonnamment pertinents . Je ne pense pas que votre réponse soit mauvaise, mais je suis sûr que cela n'aiderait pas l'éternelle dépression de Bjarne Stroustrup à cause du regret de confier le contrôle de l'avenir de C ++ à un comité très indécis.
whn
4
@snb Je suis d'accord pour dire que créer piune constante polymorphe est la voie à suivre - dans un langage avec l'inférence de type Hindley-Milner. Dans Haskell, nous l'avons toujours fait pi :: Floating a => a, donc cela piaurait automatiquement la valeur 3.1415927dans un Floatcontexte, 3.141592653589793dans un Doublecontexte et πdans un contexte de calcul symbolique. Mais les gens aimeraient-ils vraiment avoir à instancier explicitement le paramètre de modèle? Cela semble un peu gênant, surtout si une long doubleimplémentation fixe donnerait des résultats identiques dans la plupart des applications.
gauche autour du
2
@leftaroundabout Je crois qu'écrire auto a = pi<float>;est tout à fait bien, certainement plus lisible que notoire4*atan(1)
Amomum
1
Ugh, j'ai critiqué ceci par erreur de clic et maintenant je ne peux pas l'annuler. Désolé. Cela mérite un +1 pour une assez bonne explication du raisonnement du comité expliquant pourquoi il n'a pas été ajouté, même si je pense personnellement que le raisonnement est fondamentalement défectueux pour les raisons que les gens ont déjà soulignées.
Fonder le procès de Monica le
-1

Modifié - Pour supprimer le terme nécessaire, car il s'est avéré controversé. C'est trop un terme absolu.

C ++ est un langage volumineux et complexe, c'est pourquoi le Comité des normes n'inclut que les éléments fortement requis . Autant que possible est laissé aux bibliothèques standard non linguistiques ... comme Boost.
boost :: math :: constantes

Tiger4Hire
la source
29
Bien sûr, std::hermiteet std::cyl_bessel_iet std::coshet std::mersenne_twister_engineet std::ranlux48et std::cauchy_distributionet std::assoc_laguerreet std::betatous étaient absolument nécessaires, nous les utilisons tous tous les jours!
Amomum
2
Je suis à peu près sûr que vous ne pourriez même pas convaincre le comité lui-même d'approuver l'idée que tout ce pour quoi il vote est «absolument nécessaire». Il ne s'agit pas de nécessité mais d'ajouter de la valeur au langage - presque rien dans la bibliothèque standard n'est nécessaire pour écrire des programmes, et d'ailleurs la plupart du langage de base peut également être jeté (si cela ne vous dérange pas de travailler dans un Turing tarpit, c'est-à-dire). La valeur de l'inclusion d'une constante pour pi peut être débattue, mais l'idée que ce n'est pas là parce que ce n'est tout simplement pas nécessaire ne tient pas la route.
Jeroen Mostert
Ne vous plaignez pas de moi, je cite simplement le comité des normes. Il y a eu de longues discussions ouvertes sur la quantité de boost à inclure dans la norme C ++ 11. La raison pour laquelle un si petit sous-ensemble l'a fait est que les rédacteurs du compilateur se sont plaints de la quantité de tests impliqués. Par conséquent, si quelque chose est dans les normes, c'est là parce que quelqu'un a jugé nécessaire de le normaliser. Ce n'est pas parce que vous ne savez pas pourquoi, qu'il n'y avait aucune raison.
Tiger4Hire
1
@ Tiger4Hire Je suis sûr qu'il y a une raison à tout, je ne peux tout simplement pas comprendre pourquoi la constante pour pi n'a pas été ajoutée alors que beaucoup de choses plus complexes l'étaient. Constant est facile à écrire avec des modèles de variables et ne nécessitera pas beaucoup de tests de la part des rédacteurs du compilateur.
Amomum
@Amomum: Oui, ajouter pi semble être une petite surcharge pour une grosse victoire. Attention, personnellement, je préférerais voir std :: network avant std :: math :: constants.
Tiger4Hire