Вводит ли C++ 11, 14, 17 или 20 стандартную константу для числа пи?

Есть довольно глупая проблема с числом пи в C и C++. Насколько мне известно, M_PI, определенный в math.h, не требуется ни одним стандартом.

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

Введены ли какие-либо из «новых» стандартов в константу для числа Пи? Если нет - почему? Как без этого будет работать вся эта сложная математика?

Мне известны аналогичные вопросы о пи в C++ (им несколько лет и стандарты); Хотелось бы узнать текущее состояние проблемы.

Меня также очень интересует почему ой почему C++ по-прежнему не имеет константы пи, но имеет много более сложной математики.

Я знаю, что могу определить пи как 4*atan(1), acos(1) или double pi = 3.14;. Конечно. Но почему я все еще должен это делать? Как стандартные математические функции работают без пи?

Вы заметили наличие старых вопросов, таких как Лучшая независимая от платформы константа Пи?. Если вы беспокоитесь, что они устарели, вы всегда можете назначить вознаграждение за одного из них, запрашивающего ответы на основе C++ 17 и т.д ... Тогда все ответы будут в одном месте. Почему все еще хороший вопрос, но, возможно, он должен быть сосредоточен на том, почему, и просьба обновлять данные должна быть наградой по существующим вопросам.

Shafik Yaghmour 13.04.2018 07:48

Я думаю, что, возможно, стоит добавить новые ответы, поскольку C++ 20 добавил константу pi, насколько мне известно

Guillaume Racicot 05.08.2019 18:18

@GuillaumeRacicot, я обновил вопрос. Не уверен, стоит ли нам обращаться к C++ 20, поскольку он еще не выпущен официально.

Amomum 05.08.2019 18:22

@GuillaumeRacicot: Уже немного поздно добавлять…

Davis Herring 10.10.2019 00:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
180
4
28 679
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

constexpr double pi = 3.14159265358979323846;

Другие языки, такие как C# имеют - константа, объявленная в их библиотеках.

Обновлять: Начиная с C++ 20, внутри заголовка pi действительно объявлена ​​константа <numbers>. Доступ к нему осуществляется через: std::numbers::pi.

Возможно, вы захотите добавить inline для C++ 17 +.

Deduplicator 11.04.2018 17:05

Та. Проголосуйте за, но обратите внимание, что ваше определение все еще уязвимо для неточностей с платформами с разными определениями double. В C# это просто, так как тип double исправлен. Если бы я был в комитете по стандартам C++, я бы предложил что-то вроде std::constants<double>::pi.

Bathsheba 11.04.2018 17:15

@Deduplicator также не является неявно встроенным constexpr ...?

Krupip 11.04.2018 17:32

@Bathsheba: double - это IEEE double в любой разумной реализации (и везде, где C соответствует Приложению F; я не уверен, есть ли у C++ аналог, но он должен). Нет веских причин рассматривать double как тип, точность которого может варьироваться. Если хотите, используйте long double.

R.. GitHub STOP HELPING ICE 11.04.2018 17:48

@Р. Достаточно справедливо, хотя в этом случае вам следует статическое утверждение на std::numeric_limits<double>::is_iec559;. Что, признаюсь, и есть у меня в "главном заголовке". Обратите внимание, что формально вам нужно проверять все типы с плавающей запятой отдельно. То, что один из них - IEEE754, не означает, что они все.

Bathsheba 11.04.2018 17:51

@snb: Для функций, и поскольку C++ 17, который это разрешил и ввел встроенные переменные, конечно же, constexpr подразумевает inline. Но объявления на уровне пространства имен внезапно не изменили своего значения.

Deduplicator 11.04.2018 18:25

@snb constexprне подразумеваетinline для переменной области пространства имен [dcl.constexpr]: Функция или статический член данных, объявленная с помощью спецификатора constexpr, неявно является встроенной функцией или переменной

Oliv 11.04.2018 19:30

А что насчет чего-то вроде 0x3.243F6A8885A308D3p+0, который дал бы абсолютно понять, сколько бит точности вы даете?

Daniel Schepler 12.04.2018 20:56

@DanielSchepler Итак, что это за «число»? Я не знал, что есть двойные числа с основанием 16.

BЈовић 13.04.2018 11:40
Ответ принят как подходящий

Вплоть до C++ 17 включительно Пи не является константой, введенной в язык, и это головная боль.

Мне повезло, что я использую увеличение, и они определяют Пи с достаточно большим количеством десятичных знаков даже для 128-битного long double.

Если вы не используете Boost, запрограммируйте его самостоятельно. Заманчиво определить его с помощью тригонометрической функции, но если вы это сделаете, вы не сможете сделать его constexpr. Точность тригонометрических функций также не гарантируется никаким известным мне стандартом (ср. std::sqrt), так что вы действительно находитесь на опасной почве, полагаясь на такую ​​функцию.

Есть способ получить значение constexpr для Пи с помощью метапрограммирования: см. http://timmurphy.org/2013/06/27/template-metaprogramming-in-c/


От C++ 20 хорошие новости. является - определение для Пи. C++ 20 добавляет некоторые математические константы в <numbers>. Например, std::numbers::pi относится к типу double.

Ссылка: https://en.cppreference.com/w/cpp/numeric/constants

Как кто-то предположил, есть еще const long double PI = acosl(-1.0L);.

Lundin 11.04.2018 17:16

@Lundin: Но, к сожалению, это не может быть constexpr, поэтому я говорю: «Определение его с помощью функции триггера - это боль»

Bathsheba 11.04.2018 17:16

Почему это имеет значение? Pi - это константа, не подлежащая изменению или чему-либо, зависящему от реализации. Просто запишите значение (в объекте const, если хотите) количества знаков, значимых для double (или какое-нибудь нелепое число, если вас интересуют гипотетические действительно длинные удвоения).

R.. GitHub STOP HELPING ICE 11.04.2018 17:47

@ R .. Моя проблема в том, что то, что сейчас кажется смешным, может стать совершенно нормальным через 20 лет или около того. (На ум приходят 640 тысяч Билла Гейтса). Я верю, что Boost будет идти в ногу с эволюцией архитектуры.

Bathsheba 11.04.2018 17:48

Запоминать значение числа Пи намного проще, чем запоминать формулу. (хотя я вообще не пытался запоминать формулу ...)

user202729 11.04.2018 18:43

@KonradRudolph - Я думал, что это было в 80-х: на основе логарифма числа кубов длиной 1 планка, составляющих наблюдаемую Вселенную. Интересно, есть ли у кого-нибудь номер поближе? И я не мог не заметить, что вы отредактировали свой комментарий; удвоение числа! Если вы удвоите его снова, вы окажетесь там, где я!

Bathsheba 11.04.2018 18:53

@Bathsheba Я только смутно вспомнил и обновил номер, когда нашел ссылку.

Konrad Rudolph 11.04.2018 18:55

@KonradRudolph - это действительно жалкий ответ: много физики происходит на субпротонном уровне. На данный момент мой аргумент о кубе длины Планка верен, и качество ответов SO, очевидно, лучше, чем на сайте fizzix.

Bathsheba 11.04.2018 18:57

@Bathsheba Я не думаю, что большая часть физики (или любой, на самом деле) требует одновременной точности в субпротонном и макроскопическом (Вселенском) масштабе. Другими словами, динамический диапазон в этом (по общему признанию, не очень хорошо написанном) ответе уже преувеличен для всех практических целей. Тем не менее, я не исключаю обратного.

Konrad Rudolph 11.04.2018 19:00

@KonradRudolph: Вы абсолютно правы, но C++ гордится тем, что является языком общего назначения, поэтому, если вам нужна необычная точность с плавающей запятой, он должен ее обеспечить. Многие физики увязли в том факте, что G Ньютона имеет ужасающую точность.

Bathsheba 11.04.2018 19:03

Насколько нужен был бы пи, если бы стандартная библиотека включала набор триггерных функций, измеряющих углы в единицах радианов 2pi? Хотя есть несколько целей, связанных с производными, интегралами и дифференциальными уравнениями, для которых полезны радианы, для большинства целей, связанных с фактическими углами, они являются примерно худшей единицей, которую можно вообразить.

supercat 11.04.2018 19:15

@supercat: он всплывает повсюду. Вероятность, финансовая математика, решения с использованием библиотек комплексных чисел, являющиеся некоторыми приложениями. C++ - это язык общего назначения, и поэтому IMHO должен иметь в своем стандарте pi.

Bathsheba 11.04.2018 19:18

@Bathsheba: Да, я полагаю, радианы в конечном итоге становятся естественной единицей для некоторых видов операций с комплексными числами из-за равенства Эйлера, но меня все еще раздражает, что нет никаких триггерных функций, которые предназначены для использования с фактическим углы. Например, использование графического преобразования "поворота" в радианах кажется мне просто тупым, поскольку, скорее всего, угол будет несколько кратным пи / 4, но четырехкратный поворот на пи / 4 не совсем дает исходная ориентация.

supercat 11.04.2018 19:30

@supercat В любом случае вы должны использовать кватернионы для вращения.

JAB 11.04.2018 23:18

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

Peter Cordes 12.04.2018 02:38

@KonradRudolph: Численное вычисление функций и констант, требующих 5000 десятичных цифр, использовалось с алгоритмом PSQL, чтобы вывести понимание теоретической физики и сократить вычисление многомерных интегралов до констант времени компиляции. См. Работу Дэвида Бейли по этому поводу. Boost.math вычисляет число Пи динамически, если оно не находится в списке предварительно вычисленных типов; это было бы требованием для любого стандартного значения пи C++.

user14717 12.04.2018 12:19

В качестве простого эксперимента постройте sin(pi*x) с 16-значным числом пи для double. Наблюдайте за дрейфом нулей греха на x * epsilon(). Было бы хорошо иметь sin_pi() и т. д., Но иногда вам просто нужно пи, потому что ваша проблема не отображается как x * pi. Вам может потребоваться более высокая точность, чем рабочая точность pi, чтобы предотвратить это наложение. Это может быть реализовано с помощью шаблонов выражений constexpr для основных типов. Объект pi для фундаментальных типов может быть неоцененной суммой типа float - полиномом в epsilon (), если хотите.

emsr 12.04.2018 16:34

В стороне, я думаю, что все основные математические функции могут иметь версии constexpr noexcept, если они имеют код ошибки (нет записи в глобальный и неизменно игнорируемый errno). double sin(double x, error_code& ec); и auto [lgval, lgsign] = lgamma(x, ec); и др.

emsr 12.04.2018 16:39

Если вам абсолютно необходима точность до определенного количества цифр, почему вы используете числа с плавающей запятой, а не фиксированные?

Cubic 13.04.2018 12:16

@Cubic: с плавающей запятой работают очень быстро, и, если вы знаете, как они себя ведут (накопление ошибок и т. д.), Они являются идеальным инструментом для многих приложений физического и финансового моделирования.

Bathsheba 13.04.2018 13:30

Точность π в Boost на самом деле находится в забавной ситуации: с одной стороны, у нас есть указанная вами константа, а с другой - это, что связано с 7-летняя ошибка.

Ruslan 23.11.2018 08:08

Никому не повезло использовать Boost

BrandonL 07.08.2019 01:19

Как говорили другие, std::pi нет, но если вам нужно точное значение PI, вы можете использовать:

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

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

Это не constexpr, но на практике оптимизирующие компиляторы, такие как gcc и clang, оценивают его во время компиляции. Однако объявление const важно для оптимизатора, чтобы он хорошо справлялся.

Это опасно, потому что функция acos() имеет бесконечный наклон на x = -1. Следовательно, этот метод полагается на реализацию acos(), чтобы в основном явно улавливать случай точного аргумента -1 и напрямую возвращать правильную константу. Лучше использовать что-то вроде 4*atan(1), который математически намного более устойчив (хороший наклон на x = 1 и умножение на 4 всегда точное с математикой с плавающей запятой).

cmaster - reinstate monica 05.08.2019 18:17

Нам не разрешается использовать std::acos в постоянном выражении. clang сообщает об этом как об ошибке. Обратите внимание, что это несоответствующее расширение, и в конечном итоге его следует исправить в gcc. Пожалуйста, обратитесь к этому отвечать для получения более подробной информации.

badola 12.09.2019 08:31

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

Пи, конечно, иррациональное число, поэтому оно не может быть правильно представлено типом любой C++. Вы можете возразить, что естественный подход состоит в том, чтобы определить его в самом большом доступном типе с плавающей запятой. Однако размер самого большого стандартного типа с плавающей запятой long double не определен стандартом C++, поэтому значение константы будет варьироваться в зависимости от системы. Хуже того, для любой программы, в которой рабочий тип не был этим самым большим типом, определение числа "пи" было бы неуместным, поскольку оно потребовало бы снижения производительности при каждом использовании числа "пи".

Для любого программиста также тривиально найти значение пи и определить свою собственную константу, подходящую для использования, поэтому включение ее в математические заголовки не дает большого преимущества.

C++ 14 дал нам шаблоны переменных. Разве они не для этого?

Amomum 11.04.2018 17:43

говорите как настоящий член комитета, говорите обо всех способах, которые невозможно сделать, несмотря на то, что был представлен ясный путь вперед. См. Удивительно подходящий пример шаблонов переменных.. Не думаю, что ваш ответ плох, но уверен, что он не поможет вечной депрессии Бьярна Страуструпа из-за сожаления о передаче контроля над будущим C++ очень нерешительному комитету.

Krupip 11.04.2018 17:48

@snb Я согласен с тем, что превращение pi в полиморфную константу - это ясный путь вперед - на языке с выводом типа Хиндли-Милнера. В Haskell у нас всегда был pi :: Floating a => a, так что pi автоматически будет иметь значение 3.1415927 в контексте Float, 3.141592653589793 в контексте Double и π в контексте символьных вычислений. Но действительно ли люди хотели бы явно создавать экземпляр параметра шаблона? Это кажется немного неудобным, особенно если фиксированная реализация long double будет давать идентичные результаты в большинстве приложений.

leftaroundabout 11.04.2018 21:59

Существует несколько независимых от платформы методы, изложенные здесь ... поэтому, хотя было бы неплохо иметь стандартизированный, у нас есть варианты.

Shafik Yaghmour 12.04.2018 00:21

Что ж, у нас также может быть новый пустой тривиальный тип __exposition_pi_t с неявным преобразованием ко всем типам чисел.

Deduplicator 12.04.2018 00:30

@leftaroundabout Я считаю, что писать auto a = pi<float>; совершенно нормально, определенно более читабельно, чем пресловутый 4*atan(1)

Amomum 12.04.2018 10:53

@Amomum да ... люди, вероятно, по-прежнему будут использовать мономорфные сокращения локально, чтобы избавиться от математических формул, но я согласен, что auto pi = std::pi<double> выглядит довольно чистым.

leftaroundabout 12.04.2018 11:11

Я могу возразить, что определение M_PI как десятичной константы с «достаточным» количеством цифр будет работать хорошо, без каких-либо проблем, о которых вы упомянули. Или, если набрать является по какой-то причине является проблемой, тогда также определите M_PI_F и M_PI_LD (последний указан для 128-битных реализаций).

Chromatix 12.04.2018 22:49

Ух, я отклонил это ошибочным щелчком, и теперь я не могу его отменить. Простите. Это заслуживает +1 за довольно хорошее объяснение аргументов комитета по поводу того, почему он не был добавлен, даже если я лично считаю, что рассуждения в корне ошибочны по причинам, которые люди уже указали.

Fund Monica's Lawsuit 14.04.2018 07:49

Они легко могли бы добавить функцию std::pi<T>(), которая гарантированно будет определена для T, являющегося всевозможным плавающим. Я не так хорошо знаком с новомодной идеей constexpr, но, по-видимому, функция тоже может быть отмечена как это.

Arthur Tacca 29.05.2019 22:44

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

Между тем, C++ 20 имеет такие константы (объединенный в последнем раунде функций C++ 20). В частности, есть как std::numbers::pi (типа double), так и шаблон переменной, который вы можете использовать, если хотите другой тип с плавающей запятой, например std::numbers::pi_v<float>.

Не стесняйтесь перефразировать мою правку, как сочтете нужным - я просто хотел добавить сюда фактическое написание новых констант для потомков.

Barry 09.10.2019 17:30

Отредактировано - удалить термин необходимо, потому что он оказался спорным. Это слишком абсолютный термин.

C++ - большой и сложный язык, по этой причине Комитет по стандартам включает только те вещи, которые являются настоятельно требуется. Насколько это возможно, оставлено неязыковым стандартным библиотекам ... например, Boost.
boost :: math :: constants

Конечно, std::hermite, std::cyl_bessel_i, std::cosh, std::mersenne_twister_engine, std::ranlux48, std::cauchy_distribution, std::assoc_laguerre и std::beta были абсолютно необходимы, мы все используем их каждый день!

Amomum 13.04.2018 11:24

Я почти уверен, что вы не смогли заставить даже сам комитет подписать идею о том, что все, за что они голосуют, «абсолютно необходимо». Речь идет не о необходимости, а о добавлении ценности языку - почти ничего такого в стандартной библиотеке необходим для написания программ, и в этом отношении большая часть основного языка также может быть отброшена (если вы не против работать в Брезент Тьюринга). Значение включения константы для числа Пи можно обсуждать, но идея о том, что ее здесь нет, потому что она просто не нужна, не выдерживает критики.

Jeroen Mostert 13.04.2018 11:38

Не жалуйтесь на меня, я просто цитирую комитет по стандартам. Долгие открытые дискуссии о том, сколько повышения должно быть включено в стандарт C++ 11. Причина, по которой его сделали такое небольшое подмножество, заключается в том, что авторы компилятора жаловались на то, сколько тестирования было задействовано. Следовательно, если что-то есть в стандартах, это потому, что кто-то посчитал необходимым стандартизировать это. То, что вы не знаете почему, не означает, что причины не было.

Tiger4Hire 13.04.2018 12:11

@ Tiger4Hire Я уверен, что для всего есть причина, я просто не могу понять, почему константа для пи не была добавлена, когда было много более сложных вещей. Константы легко написать с помощью шаблонов переменных и не потребуют длительного тестирования со стороны разработчиков компилятора.

Amomum 13.04.2018 16:33

@Amomum: Да, добавление числа Пи кажется небольшими накладными расходами для большого выигрыша. Имейте в виду, лично я бы предпочел видеть std :: network перед константами std :: math ::.

Tiger4Hire 13.04.2018 18:25

Другие вопросы по теме