C ++에서 PI 상수를 사용하는 방법


476

일부 C ++ 프로그램에서 PI 상수 및 삼각 함수를 사용하고 싶습니다. 삼각 함수를include <math.h> . 그러나이 헤더 파일에는 PI에 대한 정의가없는 것 같습니다.

PI를 수동으로 정의하지 않고 어떻게 얻을 수 있습니까?


3
@tiwo, 당신은 차이 무엇을 요구하고 3.14, 3.141592그리고 atan(1) * 4?
Nikola Malešević

21
부수적으로 cmath는 math.h 대신 C ++로 사용해야합니다. 이는 C를위한 것입니다.
juzzlin

4
느슨하게 관련 : 정의에서 직접 PI 값을 계산하는 방법에 대해서는 cise.ufl.edu/~manuel/obfuscate/pi.c 를 참조하십시오 .
lorro

답변:


537

일부 (특히 오래된) 플랫폼 (아래 주석 참조)에서 다음을 수행해야 할 수도 있습니다.

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

하나:

  1. 최신 플랫폼 (적어도 내 64 비트 Ubuntu 14.04에서는)에서 _USE_MATH_DEFINES

  2. (최근) Linux 플랫폼에는 long doubleGNU 확장으로 제공된 값도 있습니다.

    # define M_PIl          3.141592653589793238462643383279502884L /* pi */

51
#define _USE_MATH_DEFINESVisual C ++에서 #include <math.h>정의 M_PI가 뒤 따릅니다 . 감사.
Etan

3
cygwin 헤더와도 작동합니다.
Rob

24
cmath대신에 항상 포함 할 수 있습니다 math.h.
Richard J. Ross III

10
_USE_MATH_DEFINESGCC가 불만을 제기하는지 여부 를 정의한 후에도 정의 할 수 없는 정의되어 있기 때문에 __STRICT_ANSI__(아마도 당신이 -pedantic또는 -std=c++11) M_PI정의 하지 않기 때문에 정의 하지 마십시오 -D__STRICT_ANSI__. 직접 정의 할 때 매크로 대신 C ++이기 때문에해야합니다 constexpr auto M_PI = 3.14159265358979323846;.
legends2k

1
2018 년 현재, <math.h> 대신 <cmath>를 사용하도록 정답을 업데이트해야합니다.
jaskmar

170

Pi는로 계산할 수 있습니다 atan(1)*4. 이 방법으로 값을 계산하고 캐시 할 수 있습니다.


78
c ++ 11 사용자의 경우 :constexpr double pi() { return std::atan(1)*4; }
matiu

41
-1 : atan(1)*4 == 3.141592653589793238462643383279502884(대략 말하면) 작동합니다 . 나는 내기하지 않을 것입니다. 정상이고 원시 리터럴을 사용하여 상수를 정의하십시오. 왜 필요하지 않을 때 정밀도를 잃습니까?
Thomas Eding

29
로 곱셈 연산을 피할 수 있습니다 atan2(0, -1);.
legends2k

44
@matiu atan는 아닙니다 constexpr.
R. Martinho Fernandes

45
시도하지 acos(-1), 대신에 대한 필요성을 atan2.
user541686

113

요청 된 유형 (예 : float vs double)에 대해 최대 정확도로 중요한 수학 상수를 정의하는 boost를 사용할 수도 있습니다.

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

더 많은 예제 는 부스트 문서 를 확인하십시오 .


184
Boost : 1999 년 이래로 불필요하게 C ++의 복잡성을 증폭시킵니다!
Dan Molding

47
어리 석고 부분적으로 사실입니다. 반면 부스트는 때때로 표현 적으로 유용 할 수 있습니다.
BuschnicK

59
@ DanMoulding : 음. C만이 당신이 아는 유일한 언어입니까? C를 제외한 다른 모든 언어에는 C ++보다 큰 표준 라이브러리가 있습니다 (예 : Python, Haskell, C #, PHP, Delphi, Erlang, Java, ......). 개인적인 경험에서, 그 엘리트 주의자 not gonna use libs의견은 해충이며 아마도 C ++로 작성된 나쁜 소프트웨어의 가장 큰 이유 일 것입니다.
Sebastian Mach

11
@Gracchus : 응. 라이브러리가없는 (또는 새로운 C ++ 11 라이브러리가없는) C ++은 그 언어를 좋아하는 것만큼이나 모든 것을 직접 코딩하고 싶지는 않습니다. 생산적이지는 않습니다.
Sebastian Mach

14
나는 그가 크기가 아니라 복잡 하다고 말했다 . 아마도 a) 3 개의 중첩 된 네임 스페이스 및 b) pi를 단순한 상수가 아닌 템플릿 함수로 정의하는 것으로 가정합니다.
Timmmm

83

대신 FPU 유닛 온 칩에서 가져 오십시오.

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

double PI = get_PI();

40
:-) 아마도 그 플랫폼에 독립적이지 않지만 멋진 추가 이국적인 솔루션입니다!
Etan

3
난 당신이 여기 상자 밖으로 어떻게 당신을 사랑합니다;)
VivienLeger

1
나는이 답변을 좋아한다. 최적화 컴파일러가 현대의 컴파일러와 크게 관련되지 않은 늦게 유행하는 오래된 x86 플랫폼을 대상으로 할 때 특히 유용합니다. 이 Henrik에 감사드립니다!
Matt

49

필요한 정밀도로 pi를 입력하는 것이 좋습니다. 이렇게하면 계산에 계산 시간이 추가되지 않으며 헤더 나 #defines를 사용하지 않고도 이식 가능합니다. acos 또는 atan을 계산하는 것은 사전 계산 된 값을 사용하는 것보다 항상 비쌉니다.

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

28
이것이 우리가이 접근법을 취해서는 안되는 훌륭한 예입니다. 사람들은 실수, 반올림, 복사 및 붙여 넣기 등을합니다. M_PI를 사용하는 것이 올바른 접근법이라고 생각합니다.
nacho4d

10
C ++ 11 에서이 작업을 수행하는 경우 consta를 만드십시오 constexpr.
legends2k

3
@ nacho4d M_PI를 사용할 수 있다면 M_PI를 선호하지만 모든 시스템이 POSIX를 준수하는 것은 아닙니다. M_PI를 사용할 수없는 경우이 접근법이 4 * atan (1) 방법보다 낫다고 생각합니다.
m24p

2
"아 코스 또는 아탄을 계산하는 것이 항상 더 비싸다"는 것은 사실이 아닙니다. 최신 최적화 컴파일러는 표준 수학 함수에 대해 모두 알고 있으며이를 통해 지속적으로 전파 할 수 있습니다. 예 : goo.gl/BvdJyr
Nemo

2
@Nemo, Counter example : godbolt.org/g/DsAern 다른 곳에서 말했듯이, GCC만이 현재이 작업을 수행하는 것으로 보이며 기본 수학 함수를로 선언했기 때문일 수 있습니다 constexpr.
Parker Coates

47

쓰기보다는

#define _USE_MATH_DEFINES

내가 사용하는 것이 좋습니다 것 -D_USE_MATH_DEFINES또는/D_USE_MATH_DEFINES컴파일러를 컴파일러에 따라 합니다.

이렇게하면 헤더를 포함하기 전에 누군가가 헤더를 포함하는 경우에도 (#define이없는 경우) 추적하는 데 오랜 시간이 걸리는 모호한 컴파일러 오류 대신 상수가 여전히 유지됩니다.


좋은 팁. "당신"이 컴파일 단위라면, 어떤 것이 포함되기 전에 매크로가 정의되도록 할 수 있습니다. 그러나 "귀하"가 헤더 파일 인 경우 제어 할 수 없습니다.
Steve Jessop

3
실제로 "귀하"가 편집 단위 인 경우에도 ... 헤더의 순서에 따라 유지 보수 악몽을 향한 최단 경로입니다.
Matthieu M.

1
그러나 헤더의 순서에 의존 할 필요는 없습니다. # 포함하기 전에 #define을 수행하는 경우 (적어도 #undefs가 없다고 가정) 헤더가 서로를 포함하는지 여부는 중요하지 않습니다. NDEBUG에도 동일하게 적용됩니다.
Steve Jessop

1
프로젝트에서 가장 일반적인 문제는 예를 들어 Visual Studio로 컴파일하는 경우 컴파일러가 파일을 통과하는 순서를 알지 못하므로 <cmath>다른 장소에서 사용 하면 큰 고통이됩니다 (특히 포함 된 다른 라이브러리에 포함 된 경우). 헤더 가드 외부에 해당 부분을 배치하면 훨씬 나아졌지 만 지금은 그 일을 많이 할 수 없습니다. 컴파일러 지시문은 실제로 잘 작동합니다.
meneldal

40

공식 표준 라이브러리는 상수 PI를 정의하지 않으므로 직접 정의해야합니다. 따라서 귀하의 질문에 대한 답변은 "PI를 수동으로 정의하지 않고 어떻게 얻을 수 있습니까?" "아니요-또는 컴파일러 특정 확장에 의존합니다." 이식성에 대해 걱정하지 않는다면 컴파일러 매뉴얼에서 확인할 수 있습니다.

C ++를 사용하면 쓸 수 있습니다

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

그러나이 상수의 초기화가 정적 인 것은 아닙니다. 그러나 G ++ 컴파일러는 이러한 수학 함수를 내장 함수로 처리하며 컴파일시이 상수 표현식을 계산할 수 있습니다.


6
나는 보통 acos (-1)를 사용한다. M_PI, acos (-1) 및 atan (1) * 4를 테스트했을 때 동일한 값을 얻었습니다.
Micah

2
전통적인 방법은 사용하는 것입니다 4*atan(1.): atan구현하기 쉽고 4를 곱하면 정확한 연산입니다. 물론, 현대 컴파일러는 배에 필요한 정밀도로 모든 상수 (배 목표), 그리고 그것을 사용하는 완벽하게 합리적 acos(-1)또는 std::abs(std::arg(std::complex<double>(-1.,0.)))오일러의 공식의 역이며, 따라서 더 미학적 (I 추가 한 보인다보다 기쁘게하는 abs내가 '돈 때문에 복잡한 평면이 어떻게 절단되는지 또는 그것이 정의 된 경우를 기억하십시오).
tobi_s

그래서 아무도 실수로 당신이 진지하다고 생각하지 않습니다 (-_- '). 이것은 끔찍한 해결책입니다. atan 구현은 구현을 의미하는 표준에 의해 정의되지 않으며 아마도 hw 의존적입니다. 이것은 숫자가 끔찍할 수 있음을 의미하며, 일반적으로 3.14를 사용하는 것이 좋습니다. 또한 특별한 경우에도 상당히 느릴 수 있습니다.
midjji

32

math.hPosix 매뉴얼 페이지에서 :

   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

3
좋은 답변이지만 연결이 끊어졌습니다. 나는 이것을 대신 제안한다 .
Abderrahim Kitouni

30

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


27

표준 C ++에는 PI에 대한 상수가 없습니다.

많은 C ++ 컴파일러 정의 M_PIcmath(또는에서 math.h표준이 아닌 확장으로 C의 경우). 당신이 #define _USE_MATH_DEFINES그것을보기 전에해야 할 수도 있습니다 .


18

나는 할것이다

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

또는

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

나는 것 없는 당신이 필요로하는 정밀도에 π를 입력 . 그게 무슨 뜻입니까? 당신이 필요로하는 정밀도 의 정밀도입니다 T만, 우리는 약 아무것도 몰라T .

당신은 말할 수 있습니다 : 당신은 무엇에 대해 이야기하고 있습니까? Tfloat, double또는 long double. 그래서, 단지의 정밀도를 입력 long double, 즉,

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

그러나 미래에는 표준보다 새로운 정밀도를 가진 새로운 부동 소수점 유형이 없다는 것을 정말로 알고 long double있습니까? 당신은하지 않습니다.

이것이 첫 번째 솔루션이 아름다운 이유입니다. 표준이 새로운 유형의 삼각 함수에 과부하가 걸리는 것을 확신 할 수 있습니다.

초기화시 삼각 함수의 평가가 성능 저하라고 말하지 마십시오.


1
arg(log(x)) == π모두 를 위해 0 < x < 1.
0xbadf00d

이것은 끔찍한 생각입니다. 형식 별 오버로드 된 템플릿 constexpr을 사용하면 컴파일 오류가 발생하여 새 형식이 나타나면이를 강제로 정의 할 수 있습니다. 삼각 유형이 부동 소수점 유형으로 제한되지 않기 때문에 일반적으로 끔찍합니다. 따라서 atan (1) 실수를 즐기십시오 ... 표준은 삼각 함수가 실제 삼각 값을 유형의 정확도로 계산한다고 보장하지는 않습니다. 그것들은 일반적으로 그렇지 않으며, 예를 들어 fastmath와 함께 악화되고 항상 특별한 가치에 대해 나쁘다.
midjji

10

모든 기반을 다루는 프로젝트의 공통 헤더 중 하나에서 다음을 사용합니다.

#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>. VC ++에만 필요한`#define _USE_MATH_DEFINES를 추가 할 필요는 없습니다.

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

downvoter가이 답변의 문제점에 대해 언급 할 수 있습니까? 이것은 실제 시스템에서 잘 연구되고 테스트되어 사용되고 있습니다. 뭔가 잘못되면 분명히 개선하고 싶었습니다.
Shital Shah

1
참고로, Borland C ++ 컴파일러도 M_PI필요없이 정의합니다_USE_MATH_DEFINES
Remy Lebeau

8

나는 const double PI = 2*acos(0.0);모든 구현이 당신을 위해 그것을 제공하는 것은 아니기 때문에 일반적으로 내 자신을 정의하는 것을 선호 합니다.

이 함수가 런타임에 호출되는지 또는 컴파일 타임에 정적인지에 대한 질문은 일반적으로 한 번만 발생하기 때문에 문제가되지 않습니다.


8
acos (-1)도 파이입니다.
Roderick Taylor

3
메모리 위치에서 피연산자를 읽는 것보다 즉각적인 피연산자를로드하는 것이 CPU 명령 및 / 또는 대기 시간이 적은 경우가 많습니다. 또한 컴파일 타임에 알려진 표현식 만 사전 계산 될 수 있습니다 ( double x = pi * 1.5;예 : 등). 엄격한 루프에서 바삭 바삭한 수학에서 PI를 사용하려는 경우 컴파일러에 값을 알려주는 것이 좋습니다.
Eugene Ryabtsev

7

방금 C ++ 14 이상에 대한 유용한 팁이있는 Danny Kalev의 기사보았습니다 .

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

나는 템플릿이 유형에 따라 사용할 수 있기 때문에 이것이 매우 멋지다고 생각했다.

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>

4

M_PI, M_PI_2, M_PI_4 등과 같은 값은 표준 C ++이 아니므로 constexpr이 더 나은 솔루션으로 보입니다. 동일한 pi를 계산하는 다른 const 표현식을 공식화 할 수 있으며, 전체 정확도를 제공하는지 여부와 관련이 있습니다. C ++ 표준에는 pi 계산 방법이 명시 적으로 언급되어 있지 않습니다. 따라서 수동으로 pi를 정의하는 경향이 있습니다. 나는 모든 종류의 pi를 완벽하게 지원하는 솔루션을 아래에서 공유하고 싶습니다.

#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;
}

2
아주 좋아요 해당 번호의 끝에 "l"또는 "L"이 필요할 수 있습니다. Linux의 컴파일러 gcc에서 좁히는 경고가 발생합니다.
그랜트 Rostig

2

Windows (cygwin + g ++) 에서 in -D_XOPEN_SOURCE=500의 정의를 처리하기 위해 전 처리기에 대한 플래그를 추가해야한다는 것을 알았습니다 .M_PImath.h


2
이것은 답변이 아니라 fritzone의 답변에 대한 의견입니다.
0xbadf00d

2
@ 0xbadf00d : M_PI특정 플랫폼에서 작업하는 데 필요한 단계를 제공하는 완전 독립형 답변입니다 . 그것은 다른 플랫폼에 대한 답변이 더 이상 다른 플랫폼에 대한 답변이 아니라는 것입니다.
Ben Voigt 2016 년

2

C ++ 14를 사용하면 static constexpr auto pi = acos(-1);


9
std::acos이 아닙니다 constexpr. 따라서 코드가 컴파일되지 않습니다.
0xbadf00d

@ 0xbadf00d 나는 g ++로 컴파일했다
Willy Goat

12
@WillyGoat : 그렇다면 C ++ 14 acos가 아니기 때문에 g ++가 잘못 되었고 C ++ 17에서도 constexpr제안되지 않았 음constexpr
Ben Voigt

@ BenVoigt 어떤 수학 함수가 constexpr있습니까? 분명히 아닙니다 : stackoverflow.com/questions/17347935/constexpr-math-functions
wcochran

1
@wcochran :의 새로운 수학 함수가 많이 있습니다 constexpr(예 : github.com/kthohr/gcem ). 그러나 동일한 이름의 C 함수와 역 호환되지 않으므로 이전 이름을 대체 할 수 없습니다.
벤 Voigt

2

일부 우아한 솔루션. 삼각 함수의 정밀도는 유형의 정밀도와 같지 않습니다. 상수 값을 쓰는 것을 선호하는 사람들에게는 g ++에서 작동합니다.

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

미래의 long long long double 유형에는 256 자리 십진수 정확도가 충분해야합니다. 추가 정보가 필요한 경우 https://www.piday.org/million/을 방문 하십시오 .



1

당신은 이것을 할 수 있습니다 :

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

M_PI에 이미 정의되어 있으면 cmathinclude 이외의 다른 작업은 수행하지 않습니다 cmath. 경우 M_PI(Visual Studio에서, 예를 들면 경우 임) 정의되지 않으며, 그것을 정의 할 것이다. 두 경우 모두M_PI pi 값을 얻는 데 .

이 pi 값은 Qt Creator의 qmath.h에서 가져옵니다.


1

당신은 그것을 사용할 수 있습니다 :

#define _USE_MATH_DEFINES // for C++
#include <cmath>

#define _USE_MATH_DEFINES // for C
#include <math.h>

수학 상수는 표준 C / C ++에 정의되어 있지 않습니다. 이를 사용하려면 먼저 정의해야 _USE_MATH_DEFINES다음을 포함 cmathmath.h.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.