C ++ 11, 14, 17 veya 20 pi için standart bir sabit getiriyor mu?


171

C ve C ++ 'da pi sayısı ile oldukça aptalca bir sorun var. Bildiğim kadarıyla M_PItanımlanan math.hherhangi bir standart için gerekli değildir.

Yeni C ++ standartları, standart kütüphanede çok fazla karmaşık matematik getirdi - hiperbolik fonksiyonlar std::hermiteve std::cyl_bessel_ifarklı rasgele sayı üreteçleri vb.

'Yeni' standartlardan herhangi biri pi için bir sabit getirdi mi? Değilse - neden? Tüm bu karmaşık matematik onsuz nasıl çalışır?

C ++ 'da pi hakkında benzer soruların farkındayım (birkaç yıl ve standartlar eski); Sorunun mevcut durumunu bilmek istiyorum.

Ayrıca neden C ++ hala bir pi sabiti yok ama çok daha karmaşık matematik var neden çok ilgileniyorum .

UPD: Pi'yi kendimi 4 * atan (1) veya acos (1) veya double pi = 3.14 olarak tanımlayabileceğimi biliyorum. Elbette. Ama neden 2018'de hala yapmam gerekiyor? Standart matematik fonksiyonları pi olmadan nasıl çalışır?

UPD2: Temmuz 2019'da Köln'de yapılan C ++ Komitesi toplantısı için yapılan bu gezi raporuna göre P0631 (matematik sabitleri) teklifi C ++ 20'ye kabul edildi. Sonunda standart kütüphanede pi sayısı olacak gibi görünüyor!


En iyi platformdan bağımsız pi sabiti gibi eski soruların varlığına dikkat çekiyor musunuz? . Eğer güncelliğini yitirirseniz, C ++ 17 vb. Temelli cevaplar isteyen birisine her zaman bir ödül koyabilirsiniz ... Sonra tüm cevaplar tek bir yerde olacaktır. Neden hala iyi bir soru ama belki de bu neden ve güncel soru sormanın mevcut sorular üzerinde bir lütuf olması gerektiğine odaklanmalıdır.
Shafik Yaghmour

C ++ 20 bildiğim kadarıyla bir pi sabiti eklediğinden yeni cevaplar eklemeye değer olabilir
Guillaume Racicot

@GuillaumeRacicot soruyu güncelledim. Henüz resmi olarak yayınlanmadığından C ++ 20'yi ele almamız gerekip gerekmediğinden emin değilim.
Amomum

@GuillaumeRacicot: Bir tanesini eklemek için biraz geç…
Davis Herring

Yanıtlar:


101

C ++ 17 pi'ye kadar ve dahil olmak , dile eklenen bir sabit değildir ve boyunda bir ağrıdır.

Bence bu kullanım içinde şanslıyım artırmak ve onlar tanımlayan pi bile 128 bit ondalık basamak yeterli büyüklükte bir sayı ile long double.

Boost kullanmazsanız, kendiniz sabit kodlayın. Bir trigonometrik işlevle tanımlamak cazip gelebilir, ancak bunu yaparsanız, bunu yapamazsınız constexpr. Trigonometrik fonksiyonlar doğruluğu da (herhangi standart I bilmesi tarafından garanti edilmemektedir cf . std::sqrtÖylesine gerçekten gerçekten böyle bir işlevi güvenerek tehlikeli zeminde).

Meta programlamayı kullanarak piconstexpr için bir değer elde etmenin bir yolu vardır : bkz. Http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


C ++ 20'den bazı iyi haberler. Orada olduğu için defininition pi . C ++ 20 bazı matematiksel sabitler ekler <numbers>. Örneğin std::numbers::pibir doubletür.

Referans: https://en.cppreference.com/w/cpp/numeric/constants


9
@Lundin: Ama bu constexprne yazık ki olamaz , bu yüzden "Bir trig fonksiyonu ile tanımlamak acıdır" diyorum
Bathsheba

9
Neden fark eder? Pi değişkendir ya da uygulamaya özel bir şey değildir. Değeri (isterseniz const nesnesinde) önemli yerlerin sayısına double(veya varsayımsal gerçekten uzun uzun çiftleri önemsiyorsanız saçma bir sayıya) yazın.
R .. GitHub BUZA YARDIMCI DURDUR

10
Bu konuda sahip olduğum sorun şu anda saçma görünen şey 20 yıl kadar mükemmel bir aklı başında olabilir. (Bill Gates'in 640 bin aklına gelir). Mimari evrime ayak uydurması için Boost'a güveniyorum.
Bathsheba


10
@KonradRudolph: Aralık azaltma uygulandığında yüksek hassasiyetli bir pi önemlidir. Örneğin, x86 / x87'nin dahili Pi sabiti (tam 64 bit mantis), küçük girdiler için en son durumda " en az 1.37 quintillion birimi ve dört bitten daha az doğru bırakarak"fsin komutuna en kötü durum hatasına yol açar ve bu aralık azaltmanın birden çok kez sarıldığı büyük girdiler için daha da kötüsü. Bu biraz C ++ için kullanılan sabitlere teğet , ama yine de temiz. long double
Peter Cordes

31

Diğerlerinin söylediği gibi hayır var std::piama kesin PIdeğer istiyorsanız şunları kullanabilirsiniz:

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

Bu C ++ uygulama dan PI bir doğru-yuvarlak değer üretir varsayar acos(-1.0), ortak ama garanti değildir .

Değil constexpr, ama pratikte gcc ve clang gibi derleyicileri optimize etmek derleme zamanında değerlendirir. constYine de, optimize edicinin iyi bir iş çıkarması önemlidir.


2
Bu tehlikelidir, çünkü acos()fonksiyonun sonsuz bir eğimi vardır x = -1. Sonuç olarak, bu yöntem acos(), temelde kesin bir -1argümanın durumunu açıkça yakalamak ve doğru sabiti doğrudan döndürmek için uygulamaya dayanır . 4*atan(1)Matematiksel olarak çok daha sağlam olan bir şeyi daha iyi kullanın (iyi davranışlanmış eğim x = 1ve 4 ile çarpma her zaman kayan nokta matematiği ile hassastır).
cmaster

1
std::acosSabit bir ifadede kullanmamıza izin verilmiyor . clang bunu hata olarak bildirir. Bunun uygun olmayan bir uzantı olduğunu ve sonunda gcc olarak düzeltilmesi gerektiğini lütfen unutmayın . Daha fazla bilgi için lütfen bu cevaba bakınız.
badola

31

C ++ 20'ye kadar, hayır, standartların hiçbiri pi (π) sayısını temsil edecek sabit getirmez. Kodunuzdaki numaraya yaklaşık olarak ulaşabilirsiniz:

constexpr double pi = 3.14159265358979323846;

C # gibi diğer diller var sabiti kendi kitaplıklarında ilan etti.

Güncelleme: C ++ 20'den başlayarak, gerçekten pide <numbers>başlık içinde bildirilen bir sabit var . Bu üzerinden erişilen: std::numbers::pi.


6
inlineC ++ 17 + için eklemek isteyebilirsiniz .
Deduplicator

8
Ta. Bir oy verin, ancak tanımınızın hala farklı tanımları olan platformlarda tutarsızlığa karşı savunmasız olduğunu unutmayın double. C # doubletürü sabit olduğundan kolay . C ++ standartlar komitesinde olsaydım şöyle bir şey std::constants<double>::pi
Bathsheba

11
@ Duplicalica da constexpr örtük satır içi değil ...?
whn

4
@R. std::numeric_limits<double>::is_iec559;Bu durumda statik iddiada bulunmanıza rağmen, yeterince adil . İtiraf ediyorum ki, "ana başlığımda" olan şey budur. Resmi olarak tüm kayan nokta türlerini ayrı ayrı kontrol etmeniz gerektiğini unutmayın. Biri IEEE754 olduğu için hepsinin olduğu anlamına gelmez.
Bathsheba

2
@DanielSchepler Peki, bu "sayı" ne olmalı? 16 üssü olan çift sayı olduğunu bilmiyordum.
BЈовић

29

M_PIbir dil standardı değilse "standart" ile tanımlanır : X / Açık Sistem Arabirimleri uzantısına sahip POSIX (resmi UNIX markası için çok yaygın olarak desteklenen ve gereklidir).

C ++ 20'de ne olacağı kesin değil, ama sorduğunuzdan beri muhtemelen böyle sabitleri olacak . Makale, C ++ 20 özelliklerinin son turunda birleştirildi (Ağustos 2019'daki Komite Taslağı için).

Özellikle, farklı bir kayan nokta türü istiyorsanız, örneğin kullanabileceğiniz std::numbers::pi(tür double) ve değişken bir şablon olacaktır std::numbers::pi_v<float>. Sabitlerin tam listesi [numbers.syn] içinde görülebilir .


Uygun gördüğünüzde düzenlememi yeniden yazmaktan çekinmeyin - sadece burada yeni sabitlerin gelecek nesiller için gerçek yazımını eklemek istedim.
Barry

12

Açıkçası iyi bir fikir değildir, çünkü etki alanlarında evrensel olarak uygulanabilir pi'yi tanımlayan belirgin bir tür yoktur.

Pi, elbette, irrasyonel bir sayıdır, bu nedenle herhangi bir C ++ türü ile doğru bir şekilde temsil edilemez . Bu nedenle, doğal yaklaşımın onu mevcut en büyük kayan nokta tipinde tanımlamak olduğunu iddia edebilirsiniz. Bununla birlikte, en büyük standart kayan nokta türünün boyutu long doubleC ++ standardı tarafından tanımlanmamıştır, bu nedenle sabitin değeri sistemler arasında değişecektir. Daha da kötüsü, çalışma türünün bu en büyük tür olmadığı herhangi bir program için, pi'nin tanımı, pi'nin her kullanımı için bir performans maliyeti getireceği için uygun olmaz.

Herhangi bir programcının pi değerini bulması ve kullanıma uygun kendi sabitini tanımlaması da önemlidir, bu nedenle bunu matematik başlıklarına dahil etmek için büyük bir avantaj sağlamaz.


10
C ++ 14 bize değişken şablonlar verdi. Onlar ne için değil mi?
Amomum

21
gerçek bir komite üyesi gibi konuşulursa, ileriye yönelik açık bir yol olmasına rağmen, yapılamayacağı tüm yollar hakkında konuşun. Şaşırtıcı derecede alakalı Değişken Şablonları örneğine bakın . Cevabınızın kötü olduğunu düşünmüyorum, ama eminim ki Bjarne Stroustrup'un C ++ 'ın geleceğini kontrolünü çok kararsız bir komiteye teslim etme pişmanlığına dair ebedi depresyonuna yardımcı olmaz.
whn

4
@snb piPolimorfik bir sabit oluşturmanın, Hindley-Milner türü çıkarımlı bir dilde ileriye giden açık yol olduğunu kabul ediyorum . Haskell'de her zaman sahip olduk pi :: Floating a => a, böylece piotomatik olarak 3.1415927bir Floatbağlamda, 3.141592653589793bir Doublebağlamda ve πsembolik hesaplama bağlamında değere sahip olacaktık . Ancak insanlar, şablon parametresini açıkça başlatmak zorunda kalmak ister mi? Özellikle sabit bir long doubleuygulama çoğu uygulamada aynı sonuçları verirse biraz garip görünüyor .
leftaroundabout

2
@ leftaroundabout Yazmanın auto a = pi<float>;tamamen iyi olduğuna inanıyorum , kesinlikle daha okunaklı4*atan(1)
Amomum

1
Ugh, bunu yanlış seçerek reddettim ve şimdi geri alamıyorum. Afedersiniz. Bu, şahsen akıl yürütmenin insanların işaret ettiği nedenlerden dolayı kişisel olarak kusurlu olduğunu düşünmeme rağmen, komitenin neden eklenmediğine dair gerekçesinin oldukça iyi bir açıklaması için + 1'i hak ediyor.
Monica'nın Davası

-1

Düzenlendi - Gerekli terimi kaldırmak için, çünkü tartışmalı olduğu kanıtlandı. Çok fazla mutlak bir terim.

C ++ büyük ve karmaşık bir dildir, bu nedenle Standartlar Komitesi yalnızca çok gerekli olan şeyleri içerir . Mümkün olduğunca Boost gibi dil dışı standart kütüphanelere bırakılır.
artırmak :: matematik :: sabitleri


29
Tabii ki, std::hermiteve std::cyl_bessel_ive std::coshve std::mersenne_twister_engineve std::ranlux48ve std::cauchy_distributionve std::assoc_laguerreve std::betahepsi ve kesinlikle gerekliydi, hepimiz onları her gün kullanıyoruz!
Amomum

2
Eminim ki komite bile oy verdikleri her şeyin "kesinlikle gerekli" olduğu fikrinden vazgeçemedi. Bu bir zorunluluk değil, dile değer katmakla ilgili - program yazmak için standart kütüphanede neredeyse hiçbir şey gerekli değildir ve bu nedenle temel dilin çoğu da dışarı atılır (eğer bir Turpit tarpit, yani). Pi için bir sabitin dahil edilmesinin değeri tartışılabilir, ancak orada olmadığı fikri, sadece gerekli olmadığı için su tutmaz.
Jeroen Mostert

Bana şikayet etme, sadece standartlar komitesinden alıntı yapıyorum. C ++ 11 standardına ne kadar desteğin dahil edilmesi gerektiği konusunda uzun süredir açık tartışmalar yapıldı. Böyle küçük bir alt kümenin bunu yapmasının nedeni, derleyici yazarlarının ne kadar testin yapıldığı hakkında şikayet etmeleridir. Bu nedenle, standartlarda bir şey varsa, oradadır çünkü biri onu standartlaştırmanın gerekli olduğunu düşündü. Sadece nedenini bilmediğin için hiçbir sebep olmadığı anlamına gelmez.
Tiger4Hire

1
@ Tiger4Hire Her şeyin sebebi olduğuna eminim, çok daha karmaşık şeyler olduğunda pi için sabitin neden eklenmediğini anlayamıyorum. Constant, değişken şablonlarla yazmak kolaydır ve derleyici yazarlarından çok fazla test gerektirmez.
Amomum

@Amomum: Evet, pi eklemek büyük bir galibiyet için küçük bir yük gibi görünüyor. Zihin, kişisel olarak std :: math :: sabitlerden önce std :: network'ü görmeyi tercih ederim.
Tiger4Hire
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.