Как использовать константу PI в С++

Я хочу использовать константу PI и тригонометрические функции в некоторой программе на С++. Я получаю тригонометрические функции с include <math.h>. Однако в этом заголовочном файле не существует определения для PI.

Как я могу получить PI, не определяя его вручную?

Ответ 1

На некоторых (особенно старых) платформах (см. комментарии ниже) вам может понадобиться

#define _USE_MATH_DEFINES

а затем включить необходимый файл заголовка:

#include <math.h>

а значение pi можно получить через:

M_PI

В моем math.h (2014) он определяется как:

# define M_PI           3.14159265358979323846  /* pi */

но еще раз проверьте math.h. Выдержка из "старого" math.h (в 2009 году):

/* Define _USE_MATH_DEFINES before including math.h to expose these macro
 * definitions for common math constants.  These are placed under an #ifdef
 * since these commonly-defined names are not part of the C/C++ standards.
 */

Однако:

  • на новых платформах (по крайней мере, на моем 64-битном Ubuntu 14.04) мне не нужно определять _USE_MATH_DEFINES

  • В (недавних) платформах Linux есть значения long double, также предоставляемые как расширение GNU:

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    

Ответ 2

Pi можно рассчитать как atan(1)*4. Вы можете вычислить значение таким образом и кешировать его.

Ответ 3

Вы также можете использовать boost, который определяет важные математические константы с максимальной точностью для запрашиваемого типа (т.е. float vs double).

const double pi = boost::math::constants::pi<double>();

Подробнее см. дополнительную документацию.

Ответ 4

Получите его от блока FPU на чипе вместо этого:

double get_PI()
{
    double pi;
    __asm
    {
        fldpi
        fstp pi
    }
    return pi;
}

double PI = get_PI();

Ответ 5

Я бы порекомендовал просто ввести в pi нужную вам точность. Это не добавило бы никакого времени вычисления к вашему исполнению, и оно было бы переносимым без использования каких-либо заголовков или #defines. Вычисление acos или atan всегда дороже, чем использование предварительно рассчитанного значения.

const double PI  =3.141592653589793238463;
const float  PI_F=3.14159265358979f;

Ответ 6

Вместо записи

#define _USE_MATH_DEFINES

Я бы рекомендовал использовать -D_USE_MATH_DEFINES или /D_USE_MATH_DEFINES в зависимости от вашего компилятора.

Таким образом, вы уверены, что даже в случае с кем-то, включая заголовок перед тем, как вы это сделаете (и без #define), у вас все еще будут константы, а не непонятная ошибка компилятора, на которые вам потребуется возраст для отслеживания.

Ответ 7

Поскольку официальная стандартная библиотека не определяет константу PI, вам придется ее самостоятельно определить. Итак, ответ на ваш вопрос "Как я могу получить PI, не определяя его вручную?" msgstr "Нет - или вы полагаетесь на некоторые расширения для компилятора.". Если вы не заботитесь о переносимости, вы можете проверить это руководство для компилятора.

С++ позволяет писать

const double PI = std::atan(1.0)*4;

но инициализация этой константы не гарантируется как статическая. Компилятор g++, однако, обрабатывает эти математические функции как intrinsics и способен вычислять это постоянное выражение во время компиляции.

Ответ 8

На странице Posix man math.h:

   The  <math.h>  header  shall  provide for the following constants.  The
   values are of type double and are accurate within the precision of  the
   double type.

   M_PI   Value of pi

   M_PI_2 Value of pi/2

   M_PI_4 Value of pi/4

   M_1_PI Value of 1/pi

   M_2_PI Value of 2/pi

   M_2_SQRTPI
          Value of 2/ sqrt pi

Ответ 9

Стандарт С++ не имеет константы для PI.

Многие компиляторы С++ определяют M_PI в cmath (или в math.h для C) как нестандартное расширение. Вам может потребоваться #define _USE_MATH_DEFINES, прежде чем вы сможете его увидеть.

Ответ 10

Я бы сделал

template<typename T>
T const pi = std::acos(-T(1));

или

template<typename T>
T const pi = std::arg(-std::log(T(2)));

Я бы не печатал в π точной точности. Что это значит? Точность, в которой вы нуждаетесь, - это точность T, но мы ничего не знаем о T.

Вы могли бы сказать: о чем вы говорите? T будет float, double или long double. Итак, просто введите точность long double, т.е.

template<typename T>
T const pi = static_cast<T>(/* long double precision π */);

Но знаете ли вы, что в будущем в стандарте не будет нового типа с плавающей точкой с еще большей точностью, чем long double? Вы этого не делаете.

И вот почему первое решение красиво. Вы можете быть уверены, что стандарт перегрузит тригонометрические функции для нового типа.

И, пожалуйста, не говорите, что оценка тригонометрической функции при инициализации является штрафом за производительность.

Ответ 11

Обычно я предпочитаю определять свой собственный: const double PI = 2*acos(0.0);, потому что не все его реализации предоставляют его вам.

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

Ответ 12

Я использую следующее в одном из моих общих заголовков в проекте, который охватывает все базы:

#define _USE_MATH_DEFINES
#include <cmath>

#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif

С другой стороны, все нижеперечисленные компиляторы определяют константы M_PI и M_PIl, если вы включили <cmath>. Нет необходимости добавлять `#define _USE_MATH_DEFINES, который требуется только для VС++.

x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+

Ответ 13

Я только что натолкнулся на эту статью Дэнни Калева, в которой есть отличный совет для С++ 14 и выше.

template<typename T>
constexpr T pi = T(3.1415926535897932385);

Я подумал, что это довольно круто (хотя я бы использовал там PI с наивысшей точностью), особенно потому, что шаблоны могут использовать его в зависимости от типа.

template<typename T>
T circular_area(T r) {
  return pi<T> * r * r;
}
double darea= circular_area(5.5);//uses pi<double>
float farea= circular_area(5.5f);//uses pi<float>

Ответ 14

Такие значения, как M_PI, M_PI_2, M_PI_4 и т.д., Не являются стандартными C++, поэтому constexpr кажется лучшим решением. Могут быть сформулированы различные выражения const, которые вычисляют один и тот же пи, и меня интересует, обеспечивают ли они (все) полную точность. Стандарт C++ прямо не упоминает, как рассчитать число пи. Поэтому я склоняюсь к определению числа "пи" вручную. Я хотел бы поделиться решением ниже, которое поддерживает все виды дробей с полной точностью.

#include <ratio>
#include <iostream>

template<typename RATIO>
constexpr double dpipart()
{
    long double const pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899863;
    return static_cast<double>(pi * RATIO::num / RATIO::den);
}

int main()
{
    std::cout << dpipart<std::ratio<-1, 6>>() << std::endl;
}

Ответ 15

C++ 20 std::numbers::pi

Наконец-то пришло: http://eel.is/C++draft/numbers

Я ожидаю, что использование будет как:

#include <numbers>
#include <iostream>

int main() {
    std::cout << std::numbers::pi << std::endl;
}

Я попробую, когда поддержка придет в GCC, GCC 9.1.0 с g++-9 -std=c++2a все еще не поддерживает его.

В принятом предложении описывается:

5.0. "Заголовки" [заголовки] В таблице [tab: cpp.library.headers] необходимо добавить новый заголовок <math>.

[...]

namespace std {
namespace math { 
  template<typename T > inline constexpr T pi_v = unspecified;
    inline constexpr double pi = pi_v<double>;

Существует также std::numbers::e, конечно :-) Как рассчитать постоянную Эйлера или питание Эйлера в C++?

Эти константы используют функцию шаблона переменных C++ 14: C++ 14 Шаблоны переменных: какова их цель? Любой пример использования?

В более ранних версиях проекта константа находилась под std::math::pi: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf

Ответ 16

В окнах (cygwin + g++) я нашел необходимым добавить флаг -D_XOPEN_SOURCE=500 для препроцессора для обработки определения M_PI в math.h.

Ответ 17

С++ 14 позволяет выполнять static constexpr auto pi = acos(-1);

Ответ 18

Вы можете сделать это:

#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif

Если M_PI уже определено в cmath, это не будет делать ничего, кроме include cmath. Если M_PI не определено (что, например, в Visual Studio), оно будет определять его. В обоих случаях вы можете использовать M_PI для получения значения pi.

Это значение pi происходит от Qt Creator qmath.h.

Ответ 19

Некоторые элегантные решения. Я сомневаюсь, что точность тригонометрических функций равна точности типов. Для тех, кто предпочитает писать постоянное значение, это работает для g++:

template<class T>
class X {
public:
            static constexpr T PI = (T) 3.14159265358979323846264338327950288419\
71693993751058209749445923078164062862089986280348253421170679821480865132823066\
47093844609550582231725359408128481117450284102701938521105559644622948954930381\
964428810975665933446128475648233786783165271201909145648566923460;
...
}

Точность 256 десятичных цифр должна быть достаточной для любого будущего типа long long long double. Если требуется больше, посетите https://www.piday.org/million/.