Чи вводить 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.