Чи вводить C ++ 11, 14, 17 або 20 стандартну константу для pi?


170

Існує досить нерозумна проблема з числом pi в C і C ++. Наскільки я знаю, M_PIвизначений в math.hне вимагається жодним стандартом.

Нові стандарти C ++ ввели в складну бібліотеку багато складної математики - гіперболічні функції, std::hermiteа також std::cyl_bessel_iрізні генератори випадкових чисел тощо і так далі.

Чи вводив якийсь із "нових" стандартів константу для pi? Якщо ні - чому? Як працює вся ця складна математика без неї?

Мені відомі подібні запитання щодо pi в C ++ (їм кілька років і стандарти); Я хотів би знати сучасний стан проблеми.

Мене також дуже цікавить, чому о, чому C ++ досі не має константу pi, але має багато складнішої математики.

UPD: Я знаю, що я можу визначити pi як 4 * atan (1) або acos (1) або подвійний pi = 3,14. Звичайно. Але чому в 2018 році мені все-таки потрібно це робити? Як стандартні математичні функції працюють без пі?

UPD2: Відповідно до цього звіту про поїздки на засідання Комітету C ++ у липні 2019 року в Кельні, пропозиція P0631 (математичні константи) була прийнята до C ++ 20. Так виглядає, що нарешті ми матимемо номер pi в стандартній бібліотеці!


Ви відзначаєте наявність старих питань, таких як Best platform незалежна пістава? . Якщо ви переживаєте, що вони застаріли, ви завжди можете встановити виграш на одному з них, просячи відповіді на основі C ++ 17 тощо. Тоді всі відповіді опиняться в одному місці. Чому це все-таки гарне запитання, але, можливо, це слід зосередити на тому, чому і просити його в актуальному стані має бути принадою для існуючих питань.
— Шафік Ягмур

Думаю, варто додати нових відповідей, оскільки C ++ 20 додав pi константу, наскільки я знаю
— Гійом Рачикот

@GuillaumeRacicot я оновив питання. Не впевнений, чи варто звертатися до C ++ 20, оскільки офіційно ще не існує.
— Amomum

@GuillaumeRacicot: Трохи пізно додати її…
— Девіс Херінг

Відповіді:


101

До і включаючи C ++ 17 pi - це не константа, яка вводиться в мову, і це біль у шиї.

Мені пощастило, що я використовую boost, і вони визначають pi з достатньо великою кількістю десяткових знаків навіть для 128 біт long double.

Якщо ви не використовуєте Boost, тоді він сам жесткий код. Визначити його за допомогою тригонометричної функції є заманливо, але якщо ви це зробите, ви не можете зробити це a constexpr. Точність тригонометричних функцій також не гарантована жодним стандартом, про який я знаю ( пор . std::sqrt), Тож справді ви на небезпечній землі, дійсно покладаючись на таку функцію.

Існує спосіб отримати constexprзначення для pi за допомогою метапрограмування: див. Http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


З C ++ 20 кілька хороших новин. Там є defininition для пі . C ++ 20 додає деякі математичні константи в <numbers>. Наприклад std::numbers::pi, doubleтип.

Довідка: https://en.cppreference.com/w/cpp/numeric/constants


9
@Lundin: Але це, на constexprжаль, не може бути , тому я кажу "Визначити це функцією триггера - це біль"
— Вірсавія,

9
Чому це важливо? Pi - це константа, не підлягає змінам або будь-якому конкретному впровадженню. Просто випишіть значення (в об'єкті const, якщо вам подобається) кількість місць, значущих для double(або якесь смішне число, якщо ви дбаєте про гіпотетичні дійсно довгі подвійні дублі).
— R .. GitHub ЗАСТАНОВИТИ ДІЙ

10
@ R .. Проблема, яку я маю з цим, - це те, що зараз виглядає смішно, може стати ідеально здоровим через 20 років. (Пам’яті Біллу Гейтсу 640 тис.) Я довіряю Boost не відставати від розвитку архітектури.
— Вірсавія


10
@KonradRudolph: Висока точність пі важлива, якщо впроваджується скорочення дальності. Наприклад, внутрішня константа Pi x86 / x87 (повна 64-розрядна мантіса) призводить до найгіршої помилки для невеликих входів до fsinінструкції "приблизно 1,37 квинтільйонних одиниць останнього місця, залишаючи менше чотирьох біт правильних" , і це ще гірше для великих входів, де скорочення діапазону обертається багаторазово. Це дещо дотично до констант, що використовуються long doubleв C ++, але акуратно все одно.
— Пітер Кордес

31

Як говорили інші, немає, std::piале якщо ви хочете точного PIзначення, ви можете використовувати:

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

Це передбачає, що ваша C ++ реалізація створює коректно закруглене значення PI acos(-1.0), що є загальним, але не гарантованим .

Це не так constexpr, але на практиці оптимізація компіляторів, таких як gcc і clang, оцінюють це під час компіляції. Заявивши, що constоптимізатору важливо зробити хорошу роботу.


2
Це небезпечно, оскільки acos()функція має нескінченний нахил у x = -1. Отже, цей метод покладається на acos()реалізацію, щоб в основному явно зафіксувати випадок точного -1аргументу та повернути правильну константу безпосередньо. Краще використовувати щось на зразок 4*atan(1)математично набагато надійнішого (добре нахилений нахил на x = 1та множення на 4 завжди точно з математикою з плаваючою комою).
— cmaster - відновити

1
Нам заборонено використовувати std::acosв постійному виразі. clang повідомляє про це як про помилку. Будь ласка, зауважте, що це розширення, що не відповідає, і в кінцевому підсумку має бути зафіксовано в gcc. Будь ласка, зверніться до цієї відповіді для отримання більш детальної інформації.
— badola

31

До C ++ 20, ні, жоден із стандартів не вводить константу, яка б представляла значення число pi (π). Ви можете приблизно визначити число у своєму коді:

constexpr double pi = 3.14159265358979323846;

Інші мови, такі як C # , константно декларуються у своїх бібліотеках.

Оновлення: Починаючи з C ++ 20, дійсно piконстанта оголошується всередині <numbers>заголовка. Доступ до нього здійснюється через: std::numbers::pi.


6
Ви можете додати inlineдля C ++ 17 +.
— Дедуплікатор

8
Та. Зазначимо, але зауважте, що ваше визначення все ще вразливе до неточності з платформами з різними визначеннями double. C # це легко, оскільки doubleтип фіксований. Якби я був у комітеті зі стандартів С ++, я запропонував щось подібнеstd::constants<double>::pi
— Вірсавія

11
@Deduplicator також не чітко вбудований constexpr ...?
— WHN

4
@R. Досить справедливо, хоча std::numeric_limits<double>::is_iec559;у цьому випадку слід статично стверджувати . Що, я зізнаюся, те, що я маю в своєму «головному заголовку». Зауважте, що формально потрібно перевірити всі типи плаваючої точки окремо. Тільки тому, що IEEE754 - це не означає, що вони всі є.
— Вірсавія

2
@DanielSchepler Отже, яке це "число" повинно бути? Я не знав, що є подвійні числа з 16 базовими.
— BЈоviћ

29

M_PIвизначається "стандартним", якщо не мовним стандартом: POSIX з розширенням X / Open System Interfaces (що дуже часто підтримується і потрібно для офіційного брендингу UNIX).

Невідомо, що буде у C ++ 20, але оскільки ви запитали: напевно, такі константи будуть мати . Документ було об'єднано в останньому турі функцій C ++ 20 (для проекту Комітету в серпні 2019 року).

Зокрема, буде як std::numbers::piтип (тип double), так і змінний шаблон, який ви можете використовувати, якщо ви хочете іншого типу з плаваючою точкою, наприклад std::numbers::pi_v<float>. Повний список констант можна переглянути в [numbers.syn] .


Не соромтесь переробити мою редакцію так, як вважаєте за потрібне - я просто хотів додати насправді написання нових констант для нащадків.
— Баррі

12

Це, очевидно, не є хорошою ідеєю, оскільки не існує очевидного типу, за допомогою якого визначати pi, що є загальноприйнятним для всіх доменів.

Pi, звичайно, ірраціональне число, тому його неможливо правильно представити жодним типом C ++. Ви можете стверджувати, що природний підхід, таким чином, полягає у визначенні його у найбільшому доступному типі плаваючої точки. Однак розмір найбільшого стандартного типу з плаваючою точкоюlong double не визначається стандартом C ++, тому значення константи буде змінюватися між системами. Гірше, що для будь-якої програми, в якій робочий тип не був цим найбільшим типом, визначення pi було б недоречним, оскільки воно накладало б витрати на продуктивність при кожному використанні pi.

Будь-яке тривіальне значення також для будь-якого програміста знайти значення pi та визначити власну константу, придатну для використання, тому не дає великої переваги включити його до заголовків математики.


10
C ++ 14 дав нам змінні шаблони. Чи не для чого вони?
— Amomum

21
говоріть як справжній член комітету, говоріть про всі способи, як це неможливо зробити, незважаючи на те, що представлений чіткий шлях вперед Дивіться дивовижний приклад шаблонів змінних шаблонів . Я не думаю, що ваша відповідь є поганою, але я впевнений, що це не допоможе вічній депресії Б'ярна Струструпа з приводу жалю здати контроль над майбутнім C ++ дуже нерішучому комітету.
— пн

4
@snb Я погоджуюсь, що зробити piполіморфну ​​константу - це чіткий шлях вперед - мовою з висновком типу Гіндлі-Мілнера. У Haskell у нас завжди було pi :: Floating a => aтак, що piавтоматично матиме значення 3.1415927у Floatконтексті, 3.141592653589793у Doubleконтексті та πу символічно-обчислювальному контексті. Але чи хотілося б людям явно інстанціювати параметр шаблону? Здається трохи незручно, особливо якщо фіксована long doubleреалізація дала б однакові результати у більшості програм.
— Ліворуч близько

2
@leftaroundabout Я вважаю, що писати auto a = pi<float>;цілком чудово, звичайно, читабельніше, ніж горезвісне4*atan(1)
— Amomum

1
Фу, я спростував це помилковим клацанням, і тепер не можу його скасувати. Вибачте. Це заслуговує +1 для досить гарного пояснення мотивів комітету, чому його не було додано, навіть якщо я особисто вважаю, що міркування принципово хибні з причин, на які люди вже вказали.
— Позов по

-1

Відредаговано - Вилучити термін потрібно, оскільки він виявився суперечливим. Це занадто багато абсолютного терміна.

C ++ - велика і складна мова, тому Комітет з стандартів включає лише речі, які дуже потрібні . Якнайбільше залишається для немовних стандартних бібліотек ... типу Boost.
boost :: math :: константи


29
Звичайно, std::hermiteі std::cyl_bessel_iта std::coshі std::mersenne_twister_engineта std::ranlux48і std::cauchy_distributionта std::assoc_laguerreі std::betaвсі були абсолютно необхідні, всі ми використовуємо їх кожен день!
— Amomum

2
Я впевнений, що вам не вдалося змусити навіть сам комітет підписатися на думку про те, що все, за що вони голосують, "абсолютно необхідне". Йдеться не про необхідність, а про додавання вартості мові - майже нічого в стандартній бібліотеці не потрібно писати програм, і з цього приводу більшість основних мов можна також викинути (якщо ви не проти працювати з Тюрінг Тюрін, тобто). Значення включення константи для pi можна обговорювати, але думка, що її немає там, оскільки це просто не потрібно, не тримає води.
— Jeroen Mostert

Не нарікайте на мене, я просто цитую комітет зі стандартів. Проводилися довгі відкриті дискусії про те, яка кількість стимулів повинна бути включена у стандарт C ++ 11. Причина, через яку таке невелике підмножина зробило це, це те, що письменники-компілятори скаржилися на те, скільки було проведено тестування. Тому, якщо щось є у стандартах, це є тому, що хтось вважав за необхідне це стандартизувати. Тільки тому, що ви не знаєте чому, не означає, що не було причини.
— Tiger4Hire

1
@ Tiger4Hire Я впевнений, що є причина у всьому, я просто не можу зрозуміти, чому константу для pi не додавали, коли було багато складніших речей. Константне легко писати зі змінними шаблонами і не вимагає багато тестування від авторів-компіляторів.
— Amomum

@Amomum: Так, додавання pi здається невеликим накладним покриттям для великої виграші. Майте на увазі, особисто я вважаю за краще бачити std :: network перед std :: math :: константами.
— Tiger4Hire
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.