ฉันต้องการใช้ค่าคงที่ PI และฟังก์ชันตรีโกณมิติในบางโปรแกรม C ++ include <math.h>
ฉันได้รับฟังก์ชันตรีโกณมิติกับ อย่างไรก็ตามดูเหมือนจะไม่มีคำจำกัดความของ PI ในไฟล์ส่วนหัวนี้
ฉันจะรับ PI โดยไม่ต้องกำหนดด้วยตนเองได้อย่างไร
ฉันต้องการใช้ค่าคงที่ PI และฟังก์ชันตรีโกณมิติในบางโปรแกรม C ++ include <math.h>
ฉันได้รับฟังก์ชันตรีโกณมิติกับ อย่างไรก็ตามดูเหมือนจะไม่มีคำจำกัดความของ PI ในไฟล์ส่วนหัวนี้
ฉันจะรับ PI โดยไม่ต้องกำหนดด้วยตนเองได้อย่างไร
คำตอบ:
ในบางแพลตฟอร์ม (โดยเฉพาะอย่างยิ่งเก่ากว่า) (ดูความคิดเห็นด้านล่าง) คุณอาจจำเป็นต้อง
#define _USE_MATH_DEFINES
จากนั้นรวมไฟล์ส่วนหัวที่จำเป็น:
#include <math.h>
และคุณค่าของ pi สามารถเข้าถึงได้ผ่าน:
M_PI
ใน my 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.
*/
อย่างไรก็ตาม:
บนแพลตฟอร์มที่ใหม่กว่า (อย่างน้อยใน Ubuntu 64 บิต 14.04) ฉันไม่จำเป็นต้องกำหนด _USE_MATH_DEFINES
บน (ล่าสุด) แพลตฟอร์ม Linux มีlong double
ค่าที่จัดเตรียมไว้ให้เป็นส่วนขยาย GNU ด้วย:
# define M_PIl 3.141592653589793238462643383279502884L /* pi */
#define _USE_MATH_DEFINES
ตามด้วย#include <math.h>
นิยามM_PI
ใน visual c ++ ขอบคุณ
cmath
math.h
_USE_MATH_DEFINES
ถ้า GCC บ่นว่าเพราะ__STRICT_ANSI__
ถูกกำหนด (บางทีคุณอาจผ่าน-pedantic
หรือ-std=c++11
) ซึ่งไม่อนุญาตให้M_PI
มีการกำหนดไว้จึง undefine -D__STRICT_ANSI__
มันด้วย เมื่อกำหนดได้ด้วยตัวเองเพราะมันของ C ++ constexpr auto M_PI = 3.14159265358979323846;
แทนแมโครที่คุณควร
สามารถคำนวณ Pi ได้atan(1)*4
ดังนี้ คุณสามารถคำนวณมูลค่าด้วยวิธีนี้และแคช
constexpr double pi() { return std::atan(1)*4; }
atan(1)*4 == 3.141592653589793238462643383279502884
(พูดโดยประมาณ) ฉันจะไม่เดิมพันกับมัน เป็นปกติและใช้ตัวอักษรดิบเพื่อกำหนดค่าคงที่ ทำไมสูญเสียความแม่นยำเมื่อคุณไม่ต้องการ?
atan2(0, -1);
หนึ่งสามารถหลีกเลี่ยงการดำเนินการคูณด้วย
atan
constexpr
acos(-1)
atan2
นอกจากนี้คุณยังสามารถใช้การเพิ่มซึ่งกำหนดค่าคงที่ทางคณิตศาสตร์ที่สำคัญด้วยความแม่นยำสูงสุดสำหรับประเภทที่ร้องขอ (เช่น float vs double)
const double pi = boost::math::constants::pi<double>();
ตรวจสอบเอกสารประกอบการส่งเสริมสำหรับตัวอย่างเพิ่มเติม
not gonna use libs
-opinion เป็นศัตรูพืชและอาจเป็นสาเหตุอันดับหนึ่งสำหรับซอฟต์แวร์ที่ไม่ดีที่เขียนใน C ++
รับจากหน่วย FPU บนชิปแทน:
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
ฉันอยากจะแนะนำเพียงพิมพ์ใน pi เพื่อความแม่นยำที่คุณต้องการ สิ่งนี้จะเป็นการเพิ่มเวลาในการคำนวณของคุณและจะสามารถพกพาได้โดยไม่ต้องใช้ส่วนหัวหรือ #defines การคำนวณ acos หรือ atan มักจะแพงกว่าการใช้ค่าที่คำนวณไว้ล่วงหน้า
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
const
constexpr
constexpr
ไม่นี้ในขณะนี้และที่มีแนวโน้มเพราะมันได้ประกาศฟังก์ชั่นพื้นฐานทางคณิตศาสตร์เป็น
แทนที่จะเขียน
#define _USE_MATH_DEFINES
ฉันอยากจะแนะนำให้ใช้-D_USE_MATH_DEFINES
หรือ/D_USE_MATH_DEFINES
ขึ้นอยู่กับคอมไพเลอร์ของคุณ
วิธีนี้คุณจะมั่นใจได้ว่าแม้ในกรณีที่มีใครบางคนรวมถึงส่วนหัวก่อนที่คุณจะทำ (และไม่มี #define) คุณจะยังคงมีค่าคงที่แทนที่จะเป็นข้อผิดพลาดของคอมไพเลอร์ที่คลุมเครือ
<cmath>
ในสถานที่ต่าง ๆ มันจะกลายเป็นความเจ็บปวดครั้งใหญ่ ถ้ามันถูกรวมอยู่ในห้องสมุดอื่นคุณจะรวม) มันคงจะดีกว่ามากถ้าพวกเขาเอาส่วนนั้นออกมานอกยามหัว แต่ก็ไม่สามารถทำอะไรได้มากในตอนนี้ คอมไพเลอร์คำสั่งทำงานได้ค่อนข้างดีแน่นอน
เนื่องจากไลบรารีมาตรฐานอย่างเป็นทางการไม่ได้กำหนดค่าคงที่ PI คุณจะต้องกำหนดด้วยตนเอง ดังนั้นคำตอบสำหรับคำถามของคุณ "ฉันจะรับ PI ได้อย่างไรโดยไม่ต้องกำหนดด้วยตนเอง" คือ "คุณไม่ - หรือใช้ส่วนขยายเฉพาะคอมไพเลอร์" หากคุณไม่กังวลเกี่ยวกับการพกพาคุณสามารถตรวจสอบคู่มือคอมไพเลอร์ของคุณสำหรับสิ่งนี้
C ++ อนุญาตให้คุณเขียน
const double PI = std::atan(1.0)*4;
แต่การเริ่มต้นของค่าคงที่นี้ไม่รับประกันว่าจะคงที่ คอมไพเลอร์ G ++ อย่างไรก็ตามจัดการฟังก์ชันคณิตศาสตร์เหล่านั้นเป็นอินทรินและสามารถคำนวณนิพจน์คงที่นี้ในเวลาคอมไพล์
4*atan(1.)
: ใช้งานatan
ง่ายและคูณด้วย 4 เป็นการดำเนินการที่แน่นอน แน่นอนคอมไพเลอร์ที่ทันสมัยพับ (มีจุดมุ่งหมายที่จะพับ) ค่าคงที่ทั้งหมดที่มีความแม่นยำที่จำเป็นและก็สมบูรณ์เหมาะสมที่จะใช้acos(-1)
หรือแม้กระทั่งstd::abs(std::arg(std::complex<double>(-1.,0.)))
ซึ่งเป็นสิ่งที่ตรงกันข้ามของสูตรออยเลอร์และทำให้มากขึ้นสกอร์ที่ชื่นชอบกว่าดูเหมือนว่า (ฉันได้เพิ่มabs
เพราะผม Don' จำไม่ได้ว่าระนาบเชิงซ้อนถูกตัดหรือว่ามันถูกนิยามไว้อย่างไร)
จากหน้า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
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 “ ส่วนหัว” [ส่วนหัว] ในตาราง [แท็บ: 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
Standard C ++ ไม่มีค่าคงที่สำหรับ PI
คอมไพเลอร์ C ++ จำนวนมากกำหนดM_PI
ในcmath
(หรือในmath.h
สำหรับ C) เป็นส่วนขยายที่ไม่ได้มาตรฐาน คุณอาจต้องทำ#define _USE_MATH_DEFINES
ก่อนที่จะเห็น
ฉันจะทำ
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
? คุณทำไม่ได้
และนั่นเป็นเหตุผลที่ทางออกแรกนั้นสวยงาม คุณสามารถมั่นใจได้ว่ามาตรฐานจะทำงานเกินฟังก์ชันตรีโกณมิติสำหรับประเภทใหม่
และโปรดอย่าพูดว่าการประเมินฟังก์ชั่นตรีโกณมิติเมื่อเริ่มต้นนั้นเป็นโทษประสิทธิภาพ
arg(log(x)) == π
0 < x < 1
ฉันใช้สิ่งต่อไปนี้ในส่วนหัวร่วมหนึ่งในโครงการที่ครอบคลุมทุกฐาน:
#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 ซึ่งจำเป็นสำหรับ VC ++ เท่านั้น
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
M_PI
โดยไม่จำเป็น_USE_MATH_DEFINES
โดยทั่วไปฉันชอบกำหนดของตัวเอง: const double PI = 2*acos(0.0);
เนื่องจากการใช้งานไม่ได้มีให้สำหรับคุณ
คำถามที่ว่าฟังก์ชั่นนี้ถูกเรียกเมื่อรันไทม์หรือเป็น static'ed ในเวลาคอมไพล์มักจะไม่เป็นปัญหาเพราะมันเกิดขึ้นเพียงครั้งเดียวเท่านั้น
double x = pi * 1.5;
และไม่ชอบ) ถ้าคุณตั้งใจจะใช้ PI ในคณิตศาสตร์ที่มีการวนซ้ำในวงแคบคุณควรตรวจสอบให้แน่ใจว่าคอมไพเลอร์เป็นที่รู้จักกันดี
ฉันเพิ่งเจอบทความนี้โดยDanny Kalevซึ่งมีเคล็ดลับที่ดีสำหรับ C ++ 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>
ค่าเช่น M_PI, M_PI_2, M_PI_4 และอื่น ๆ ไม่ใช่ C ++ มาตรฐานดังนั้น constexpr ดูเหมือนจะเป็นทางออกที่ดีกว่า การแสดงออกของ const ที่แตกต่างกันสามารถกำหนดสูตรที่คำนวณ pi เดียวกันและมันเกี่ยวข้องกับฉันว่าพวกเขา (ทั้งหมด) ให้ความแม่นยำเต็มที่กับฉันหรือไม่ มาตรฐาน 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;
}
บน Windows (Cygwin + g ++) ฉันได้พบมันจำเป็นที่จะต้องเพิ่มธง-D_XOPEN_SOURCE=500
สำหรับ preprocessor ในการประมวลผลคำจำกัดความของในM_PI
math.h
M_PI
การทำงานบนแพลตฟอร์มเฉพาะ นั่นไม่ใช่ความเห็นเกี่ยวกับคำตอบสำหรับแพลตฟอร์มอื่น ๆ อีกต่อไปว่าคำตอบสำหรับแพลตฟอร์มอื่นคือความคิดเห็นในอันนี้
C ++ 14 ให้คุณทำ static constexpr auto pi = acos(-1);
std::acos
constexpr
ไม่ได้เป็น ดังนั้นรหัสของคุณจะไม่รวบรวม
acos
ไม่ได้constexpr
อยู่ใน C ++ 14 และไม่ได้เสนอให้เป็นconstexpr
แม้แต่ใน C ++ 17
constexpr
? ไม่ชัดเจน: stackoverflow.com/questions/17347935/constexpr-math-functions
constexpr
ให้ดูตัวอย่าง ( github.com/kthohr/gcem ) แต่ไม่เข้ากันได้กับฟังก์ชั่น C ที่มีชื่อเดียวกันดังนั้นจึงไม่สามารถใช้ชื่อเดิมได้
โซลูชั่นที่หรูหรา ฉันสงสัยว่าความแม่นยำของฟังก์ชันตรีโกณมิติจะเท่ากับความแม่นยำของประเภทแม้ว่า สำหรับผู้ที่ต้องการเขียนค่าคงที่สิ่งนี้ใช้ได้กับ g ++: -
template<class T>
class X {
public:
static constexpr T PI = (T) 3.14159265358979323846264338327950288419\
71693993751058209749445923078164062862089986280348253421170679821480865132823066\
47093844609550582231725359408128481117450284102701938521105559644622948954930381\
964428810975665933446128475648233786783165271201909145648566923460;
...
}
ความแม่นยำทศนิยม 256 หลักควรเพียงพอสำหรับการพิมพ์ Double Long Long Long ในอนาคต หากเข้าชมมากขึ้นจะต้องhttps://www.piday.org/million/
#include <cmath>
const long double pi = acos(-1.L);
คุณสามารถทำได้:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
หากM_PI
ถูกกำหนดไว้แล้วในการcmath
นี้จะไม่ทำอะไรอย่างอื่นมากกว่า cmath
ได้แก่ หากM_PI
ไม่ได้กำหนดไว้ (ซึ่งเป็นกรณีตัวอย่างใน Visual Studio) จะเป็นการกำหนด ในทั้งสองกรณีคุณสามารถใช้M_PI
เพื่อรับค่า pi
ค่าของ pi นี้มาจาก qmath.h ของ Qt Creator
คุณสามารถใช้สิ่งต่อไปนี้
#define _USE_MATH_DEFINES // for C++
#include <cmath>
#define _USE_MATH_DEFINES // for C
#include <math.h>
ค่าคงที่ทางคณิตศาสตร์ไม่ได้ถูกกำหนดใน Standard C / C ++ จะใช้พวกเขาครั้งแรกที่คุณจะต้องกำหนด_USE_MATH_DEFINES
แล้วรวมหรือcmath
math.h
3.14
,3.141592
และatan(1) * 4
?