可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to use the PI constant and trigonometric functions in some C++ program. I get the trigonometric functions with include <math.h>
. However, there doesn't seem to be a definition for PI in this header file.
How can I get PI without defining it manually?
回答1:
On some (especially older) platforms (see the comments below) you might need to
#define _USE_MATH_DEFINES
and then include the necessary header file:
#include <math.h>
and the value of pi can be accessed via:
M_PI
In my math.h
(2014) it is defined as:
# define M_PI 3.14159265358979323846 /* pi */
but check your math.h
for more. An extract from the "old" math.h
(in 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.
*/
However:
on newer platforms (at least on my 64 bit Ubuntu 14.04) I do not need to define the _USE_MATH_DEFINES
On (recent) Linux platforms there are long double
values too provided as a GNU Extension:
# define M_PIl 3.141592653589793238462643383279502884L /* pi */
回答2:
Pi can be calculated as atan(1)*4
. You could calculate the value this way and cache it.
回答3:
You could also use boost, which defines important math constants with maximum accuracy for the requested type (i.e. float vs double).
const double pi = boost::math::constants::pi<double>();
Check out the boost documentation for more examples.
回答4:
Get it from the FPU unit on chip instead:
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
回答5:
I would recommend just typing in pi to the precision you need. This would add no calculation time to your execution, and it would be portable without using any headers or #defines. Calculating acos or atan is always more expensive than using a precalculated value.
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
回答6:
Rather than writing
#define _USE_MATH_DEFINES
I would recommend using -D_USE_MATH_DEFINES
or /D_USE_MATH_DEFINES
depending on your compiler.
This way you are assured that even in the event of someone including the header before you do (and without the #define) you will still have the constants instead of an obscure compiler error that you will take ages to track down.
回答7:
Since the official standard library doesn't define a constant PI you would have to define it yourself. So the answer to your question "How can I get PI without defining it manually?" is "You don't -- or you rely on some compiler-specific extensions.". If you're not concerned about portability you could check your compiler's manual for this.
C++ allows you to write
const double PI = std::atan(1.0)*4;
but the initialization of this constant is not guaranteed to be static. The G++ compiler however handles those math functions as intrinsics and is able to compute this constant expression at compile-time.
回答8:
From the Posix man page of 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:
Standard C++ doesn't have a constant for PI.
Many C++ compilers define M_PI
in cmath
(or in math.h
for C) as a non-standard extension. You may have to #define _USE_MATH_DEFINES
before you can see it.
回答10:
I would do
template<typename T>
T const pi = std::acos(-T(1));
or
template<typename T>
T const pi = std::arg(-std::log(T(2)));
I would not typing in π to the precision you need. What is that even supposed to mean? The precision you need is the precision of T
, but we know nothing about T
.
You might say: What are you talking about? T
will be float
, double
or long double
. So, just type in the precision of long double
, i.e.
template<typename T>
T const pi = static_cast<T>(/* long double precision π */);
But do you really know that there won't be a new floating point type in the standard in the future with an even higher precision than long double
? You don't.
And that's why the first solution is beautiful. You can be quite sure that the standard would overload the trigonometric functions for a new type.
And please, don't say that the evaluation of a trigonometric function at initialization is a performance penalty.
回答11:
I generally prefer defining my own: const double PI = 2*acos(0.0);
because not all implementations provide it for you.
The question of whether this function gets called at runtime or is static'ed out at compile time is usually not an issue, because it only happens once anyway.
回答12:
I use following in one of my common header in the project that covers all bases:
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif
On a side note, all of below compilers define M_PI and M_PIl constants if you include <cmath>
. There is no need to add `#define _USE_MATH_DEFINES which is only required for VC++.
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
回答13:
I just came across this article by Danny Kalev which has a great tip for C++14 and up.
template<typename T>
constexpr T pi = T(3.1415926535897932385);
I thought this was pretty cool (though I would use the highest precision PI in there I could), especially because templates can use it based on type.
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:
On windows (cygwin + g++), I've found it necessary to add the flag -D_XOPEN_SOURCE=500
for the preprocessor to process the definition of M_PI
in math.h
.
回答15:
C++14 lets you do static constexpr auto pi = acos(-1);
回答16:
You can do this:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
If M_PI
is already defined in cmath
, this won't do anything else than include cmath
. If M_PI
isn't defined (which is the case for example in Visual Studio), it will define it. In both cases, you can use M_PI
to get the value of pi.
This value of pi comes from Qt Creator's qmath.h.
回答17:
Values like M_PI, M_PI_2, M_PI_4, etc are not standard C++ so a constexpr seems a better solution. Different const expressions can be formulated that calculate the same pi and it concerns me whether they (all) provide me the full accuracy. The C++ standard does not explicitly mention how to calculate pi. Therefore, I tend to fall back to defining pi manually. I would like to share the solution below which supports all kind of fractions of pi in full accuracy.
#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;
}