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

170

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

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

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

Мне известны подобные вопросы о пи в С ++ (им уже несколько лет и они соответствуют стандартам); Я хотел бы знать текущее состояние проблемы.

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

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

UPD2: Согласно этому отчету о поездке на заседание Комитета C ++ в июле 2019 года в Кельне, предложение P0631 (математические константы) было принято в C ++ 20. Похоже, наконец-то у нас в стандартной библиотеке будет число pi!

Amomum
источник
Вы замечаете существование старых вопросов, таких как Best pi-независимая платформа? , Если вы беспокоитесь, что они устарели, вы всегда можете назначить вознаграждение одному из них, запрашивающему ответы на основе C ++ 17 и т. Д. Тогда все ответы будут в одном месте. Почему по-прежнему хороший вопрос, но, возможно, следует сосредоточиться на том, почему, а вопрос о своевременности должен быть щедрым на существующие вопросы.
Шафик Ягмур
Я думаю, что, возможно, стоит добавить новые ответы, поскольку C ++ 20, насколько я знаю, добавил константу пи
Гийом Расикот
@GuillaumeRacicot я обновил вопрос. Не уверен, стоит ли нам обращаться к C ++ 20, поскольку он официально еще не выпущен.
Amomum
@GuillaumeRacicot: Уже немного поздно, чтобы добавить один ...
Дэвис Херринг

Ответы:

101

До C ++ 17 включительно pi это не константа, введенная в язык, и это боль в шее.

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

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

Есть способ получить constexprзначение для пи с помощью метапрограммирования: см. 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 from acos(-1.0), что является обычным, но не гарантированным .

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

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

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

constexpr double pi = 3.14159265358979323846;

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

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

Рон
источник
6
Возможно, вы захотите добавить inlineдля C ++ 17 +.
Дедупликатор
8
Ta. Воздержитесь, но учтите, что ваше определение все еще уязвимо для неточности на платформах с другими определениями double. В C # это легко, поскольку doubleтип исправлен. Если бы я был в комитете по стандартам C ++, я бы предложил что-то вродеstd::constants<double>::pi
Вирсавия
11
@Deduplicator также не является встроенным в constexpr ...?
1818
4
@Р. Справедливо, хотя std::numeric_limits<double>::is_iec559;в этом случае вы должны утверждать статичность . Который, я признаюсь, является тем, что я имею в своем "главном заголовке". Обратите внимание, что формально вам нужно проверять все типы с плавающей запятой отдельно. То, что один из них - IEEE754, не означает, что они все.
Вирсавия
2
@DanielSchepler Итак, что это за «число» должно быть? Я не знал, что есть двойные числа с 16 основаниями.
BЈовић
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, конечно, иррациональное число, поэтому оно не может быть правильно представлено ни одним типом C ++. Поэтому вы можете утверждать, что естественный подход состоит в том, чтобы определить его в наибольшем доступном типе с плавающей запятой. Тем не менее, размер самого большого стандартного типа с плавающей запятойlong double не определяется стандартом C ++, поэтому значение константы в разных системах будет различным. Хуже того, для любой программы, в которой рабочий тип не был такого большого типа, определение числа «пи» было бы неуместным, так как оно накладывало бы затраты на производительность при каждом использовании числа «пи».

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

Джек Эйдли
источник
10
C ++ 14 дал нам переменные шаблоны. Разве это не то, для чего они?
Amomum
21
Говоря как настоящий член комитета, поговорите обо всех способах, которыми это невозможно сделать, несмотря на то, что будет представлен четкий путь вперед. Смотрите удивительно релевантный пример Шаблоны переменных . Я не думаю, что ваш ответ плохой, но я уверен, что это не поможет вечной депрессии Бьярна Страуструпа из-за сожаления о передаче контроля над будущим C ++ очень нерешительному комитету.
1818
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.
повышение :: Math :: константы

Tiger4Hire
источник
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 может быть обсуждено, но идея, что это не там, потому что это просто не нужно, не выдерживает критики.
Йерун Мостерт
Не жалуйтесь на меня, я просто цитирую комитет по стандартам. Были долгие открытые дискуссии о том, какая поддержка должна быть включена в стандарт C ++ 11. Причина, по которой возникло такое небольшое подмножество, заключается в том, что авторы компилятора жаловались на то, насколько много было задействовано в тестировании. Поэтому, если что-то есть в стандартах, оно есть, потому что кто-то счел необходимым стандартизировать это. То, что ты не знаешь почему, не означает, что не было никаких причин.
Tiger4Hire
1
@ Tiger4Hire Я уверен, что есть причина для всего, я просто не могу понять, почему константа для пи не была добавлена, когда было много более сложных вещей. Константу легко написать с помощью переменных шаблонов, и она не требует большого тестирования со стороны разработчиков компиляторов.
Amomum
@Amomum: Да, добавление пи похоже на небольшие накладные расходы для большой победы. Имейте в виду, лично я предпочел бы видеть std :: network перед std :: math :: constants.
Tiger4Hire