Как использовать константу PI в C ++ - PullRequest
408 голосов
/ 13 ноября 2009

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

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

Ответы [ 18 ]

481 голосов
/ 13 ноября 2009

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

#define _USE_MATH_DEFINES

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

#include <math.h>

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

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.
 */

Тем не менее:

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

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

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */
    
162 голосов
/ 13 ноября 2009

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

107 голосов
/ 13 ноября 2009

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

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

Просмотрите дополнительные документы , чтобы получить больше примеров.

66 голосов
/ 04 июня 2015

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

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

double PI = get_PI();
47 голосов
/ 13 ноября 2011

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

const double PI  =3.141592653589793238463;
const float  PI_F=3.14159265358979f;
43 голосов
/ 13 ноября 2009

Вместо написания

#define _USE_MATH_DEFINES

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

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

39 голосов
/ 13 ноября 2009

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

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

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

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

29 голосов
/ 12 марта 2013

Из справочной страницы Posix по математике из 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
26 голосов
/ 13 ноября 2009

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

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

14 голосов
/ 26 февраля 2016

Я бы сделал

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? Вы не.

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

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

...