Chcę użyć funkcji PI i funkcji trygonometrycznych w niektórych programach C ++. Dostaję funkcje trygonometryczne z include <math.h>
. Wydaje się jednak, że w tym pliku nagłówkowym nie ma definicji PI.
Jak mogę uzyskać PI bez ręcznego definiowania?
Chcę użyć funkcji PI i funkcji trygonometrycznych w niektórych programach C ++. Dostaję funkcje trygonometryczne z include <math.h>
. Wydaje się jednak, że w tym pliku nagłówkowym nie ma definicji PI.
Jak mogę uzyskać PI bez ręcznego definiowania?
Odpowiedzi:
Na niektórych (szczególnie starszych) platformach (patrz komentarze poniżej) może być konieczne
#define _USE_MATH_DEFINES
a następnie dołącz niezbędny plik nagłówka:
#include <math.h>
a wartość pi można uzyskać poprzez:
M_PI
W moim math.h
(2014) jest to zdefiniowane jako:
# define M_PI 3.14159265358979323846 /* pi */
ale sprawdź math.h
więcej. Fragment „starego” math.h
(w 2009 r.):
/* 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.
*/
Jednak:
na nowszych platformach (przynajmniej na moim 64-bitowym Ubuntu 14.04) nie muszę definiować _USE_MATH_DEFINES
Na (najnowszych) platformach Linux są long double
też wartości dostarczane jako rozszerzenie GNU:
# define M_PIl 3.141592653589793238462643383279502884L /* pi */
#define _USE_MATH_DEFINES
a następnie #include <math.h>
definicje M_PI
w Visual C ++. Dzięki.
cmath
zamiast math.h
.
_USE_MATH_DEFINES
czy GCC narzeka, że to dlatego, że __STRICT_ANSI__
jest zdefiniowane (być może zdałeś -pedantic
lub -std=c++11
zdałeś), co nie pozwala M_PI
na zdefiniowanie, dlatego nie zdefiniuj go -D__STRICT_ANSI__
. Definiując go sam, ponieważ jest to C ++, zamiast makra powinieneś constexpr auto M_PI = 3.14159265358979323846;
.
Pi można obliczyć jako atan(1)*4
. Możesz w ten sposób obliczyć wartość i zapisać ją w pamięci podręcznej.
constexpr double pi() { return std::atan(1)*4; }
atan(1)*4 == 3.141592653589793238462643383279502884
(z grubsza). Nie postawiłbym na to. Bądź normalny i użyj surowego literału, aby zdefiniować stałą. Po co tracić precyzję, kiedy nie jest to konieczne?
atan2(0, -1);
.
atan
nie jest constexpr
.
acos(-1)
Zamiast tego spróbuj atan2
.
Możesz także użyć wzmocnienia, które definiuje ważne stałe matematyczne z maksymalną dokładnością dla żądanego typu (tj. Zmiennoprzecinkowe vs podwójne).
const double pi = boost::math::constants::pi<double>();
Sprawdź dokumentację doładowania, aby uzyskać więcej przykładów.
not gonna use libs
opinia jest szkodnikiem i prawdopodobnie głównym powodem złego oprogramowania napisanego w C ++.
Zamiast tego pobierz go z jednostki FPU na chipie:
double get_PI()
{
double pi;
__asm
{
fldpi
fstp pi
}
return pi;
}
double PI = get_PI();
Polecam po prostu wpisać pi z dokładnością, jakiej potrzebujesz. To nie zwiększy czasu wykonywania obliczeń i będzie przenośne bez użycia nagłówków lub # definicji. Obliczanie acos lub atan jest zawsze droższe niż stosowanie wstępnie obliczonej wartości.
const double PI =3.141592653589793238463;
const float PI_F=3.14159265358979f;
const
a constexpr
.
constexpr
.
Zamiast pisać
#define _USE_MATH_DEFINES
Polecam używanie -D_USE_MATH_DEFINES
lub /D_USE_MATH_DEFINES
zależnie od twojego kompilatora.
W ten sposób masz pewność, że nawet w przypadku, gdy ktoś włączy nagłówek, zanim to zrobisz (i bez #define) nadal będziesz mieć stałe zamiast niejasnego błędu kompilatora, którego wyśledzenie zajmie Ci całe wieki.
<cmath>
w różnych miejscach, staje się to dużym problemem (szczególnie jeśli jest dołączony przez inną bibliotekę, którą dołączasz). Byłoby znacznie lepiej, gdyby umieścili tę część poza osłonami hedera, ale cóż, teraz niewiele można na to poradzić. Dyrektywa kompilatora działa naprawdę całkiem dobrze.
Ponieważ oficjalna biblioteka standardowa nie definiuje stałego PI, musiałbyś go zdefiniować sam. Więc odpowiedź na twoje pytanie „Jak mogę uzyskać PI bez definiowania go ręcznie?” to „Nie - lub polegasz na niektórych rozszerzeniach specyficznych dla kompilatora”. Jeśli nie martwisz się o przenośność, możesz to sprawdzić w instrukcji kompilatora.
C ++ pozwala pisać
const double PI = std::atan(1.0)*4;
ale nie można zagwarantować, że inicjalizacja tej stałej będzie statyczna. Kompilator G ++ obsługuje jednak te funkcje matematyczne jako elementy wewnętrzne i jest w stanie obliczyć to stałe wyrażenie w czasie kompilacji.
4*atan(1.)
: atan
jest łatwy do wdrożenia, a pomnożenie przez 4 jest dokładną operacją. Oczywiście współczesne kompilatory składają (dążą do złożenia) wszystkie stałe z wymaganą precyzją i jest całkowicie rozsądne w użyciu, acos(-1)
a nawet std::abs(std::arg(std::complex<double>(-1.,0.)))
odwrotne do formuły Eulera, a zatem bardziej estetyczne niż się wydaje (dodałem, abs
ponieważ nie „ pamiętaj, w jaki sposób wycina się płaszczyznę złożoną lub jeśli jest to w ogóle zdefiniowane).
Ze strony podręcznika 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
W końcu dotarł: http://eel.is/c++draft/numbers
Oczekuję, że użycie będzie takie jak:
#include <numbers>
#include <iostream>
int main() {
std::cout << std::numbers::pi << std::endl;
}
Spróbuję, kiedy wsparcie dotrze do GCC, GCC 9.1.0 z g++-9 -std=c++2a
nadal go nie obsługuje.
Przyjęta propozycja opisuje:
5.0 „Nagłówki” [nagłówki] W tabeli [tab: cpp.library.headers] nowy
<math>
nagłówek.[...]
namespace std { namespace math { template<typename T > inline constexpr T pi_v = unspecified; inline constexpr double pi = pi_v<double>;
Jest też std::numbers::e
oczywiście :-) Jak obliczyć stałą Eulera lub Eulera zasilanego w C ++?
Te stałe używają funkcji szablonu zmiennej C ++ 14: Szablony zmiennych C ++ 14: jaki jest ich cel? Dowolny przykład użycia?
We wcześniejszych wersjach projektu stała była pod std::math::pi
: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r7.pdf
Standardowy C ++ nie ma stałej dla PI.
Wiele kompilatorów C ++ definiuje M_PI
w cmath
(lub math.h
dla C) jako niestandardowe rozszerzenie. Być może będziesz musiał #define _USE_MATH_DEFINES
to zobaczyć.
chciałbym zrobić
template<typename T>
T const pi = std::acos(-T(1));
lub
template<typename T>
T const pi = std::arg(-std::log(T(2)));
Chciałbym nie wpisując Õ do precyzji trzeba . Co to w ogóle ma znaczyć? Precyzja potrzebne jest precyzja T
, ale nic o tym wiedzieć T
.
Możesz powiedzieć: o czym ty mówisz? T
będzie float
, double
albo long double
. Więc po prostu wpisz dokładność long double
, tj
template<typename T>
T const pi = static_cast<T>(/* long double precision π */);
Ale czy naprawdę wiesz, że w przyszłości nie będzie nowego typu zmiennoprzecinkowego z jeszcze większą precyzją niż long double
? Ty nie.
I dlatego pierwsze rozwiązanie jest piękne. Możesz być całkiem pewien, że standard przeciąża funkcje trygonometryczne dla nowego typu.
I proszę, nie mów, że ocena funkcji trygonometrycznych przy inicjalizacji jest ograniczeniem wydajności.
arg(log(x)) == π
dla wszystkich 0 < x < 1
.
Używam następujących w jednym z moich wspólnych nagłówków w projekcie, który obejmuje wszystkie podstawy:
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
#ifndef M_PIl
#define M_PIl (3.14159265358979323846264338327950288)
#endif
Na marginesie, wszystkie poniższe kompilatory definiują stałe M_PI i M_PIl, jeśli je uwzględnisz <cmath>
. Nie ma potrzeby dodawania `#define _USE_MATH_DEFINES, który jest wymagany tylko w VC ++.
x86 GCC 4.4+
ARM GCC 4.5+
x86 Clang 3.0+
M_PI
bez potrzeby_USE_MATH_DEFINES
Generalnie wolę zdefiniować własne: const double PI = 2*acos(0.0);
ponieważ nie wszystkie implementacje to zapewniają.
Pytanie, czy funkcja ta jest wywoływana w czasie wykonywania, czy jest statycznie wyłączana w czasie kompilacji, zwykle nie stanowi problemu, ponieważ dzieje się tak tylko raz.
double x = pi * 1.5;
i tym podobne). Jeśli kiedykolwiek zamierzasz używać PI w chrupiącej matematyce w ciasnych pętlach, lepiej upewnij się, że wartość jest znana kompilatorowi.
Właśnie natknąłem tego artykułu przez Danny Kalev który ma wielką wskazówka dla C ++ 14 i do góry.
template<typename T>
constexpr T pi = T(3.1415926535897932385);
Pomyślałem, że to całkiem fajne (chociaż użyłbym tam najwyższej precyzji PI tam, gdzie mogłem), zwłaszcza, że szablony mogą używać tego na podstawie typu.
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>
Wartości takie jak M_PI, M_PI_2, M_PI_4 itp. Nie są standardowym C ++, więc constexpr wydaje się lepszym rozwiązaniem. Można sformułować różne wyrażenia stałych, które obliczają to samo pi i dotyczy mnie to, czy (wszystkie) zapewniają mi pełną dokładność. Standard C ++ nie mówi wprost o tym, jak obliczyć pi. Dlatego zwykle wracam do ręcznego definiowania pi. Chciałbym podzielić się poniższym rozwiązaniem, które obsługuje wszystkie frakcje pi z pełną dokładnością.
#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;
}
W systemie Windows (cygwin + g ++) uważam za konieczne dodanie flagi -D_XOPEN_SOURCE=500
dla preprocesora w celu przetworzenia definicji M_PI
w math.h
.
M_PI
rozpoczęcia pracy na konkretnej platformie. To już nie jest komentarz do odpowiedzi na jakąś inną platformę, ale odpowiedź na jakąś inną platformę jest komentarzem do tej.
C ++ 14 pozwala na to static constexpr auto pi = acos(-1);
std::acos
nie jest constexpr
. Twój kod się nie skompiluje.
acos
nie ma go constexpr
w C ++ 14 i nie proponuje się, aby stał się constexpr
nawet w C ++ 17
constexpr
? Najwyraźniej nie: stackoverflow.com/questions/17347935/constexpr-math-functions
constexpr
, patrz na przykład ( github.com/kthohr/gcem ). Ale nie są one kompatybilne wstecz z funkcjami C o tej samej nazwie, więc nie mogą przejąć starych nazw.
Kilka eleganckich rozwiązań. Wątpię jednak, aby precyzja funkcji trygonometrycznych była równa precyzji typów. Dla tych, którzy wolą zapisywać stałą wartość, działa to dla g ++: -
template<class T>
class X {
public:
static constexpr T PI = (T) 3.14159265358979323846264338327950288419\
71693993751058209749445923078164062862089986280348253421170679821480865132823066\
47093844609550582231725359408128481117450284102701938521105559644622948954930381\
964428810975665933446128475648233786783165271201909145648566923460;
...
}
Dokładność 256 cyfr dziesiętnych powinna wystarczyć dla każdego przyszłego długiego, długiego, podwójnego typu. Jeśli potrzebujesz więcej, odwiedź https://www.piday.org/million/ .
Możesz to zrobić:
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
Jeśli M_PI
jest już zdefiniowane w cmath
, nie zrobi nic innego niż dołączyć cmath
. Jeśli M_PI
nie jest zdefiniowany (co ma miejsce na przykład w Visual Studio), to go zdefiniuje. W obu przypadkach możesz użyćM_PI
aby uzyskać wartość pi.
Ta wartość pi pochodzi z qmath.h Qt Creatora.
Możesz użyć tego:
#define _USE_MATH_DEFINES // for C++
#include <cmath>
#define _USE_MATH_DEFINES // for C
#include <math.h>
Stałe matematyczne nie są zdefiniowane w standardzie C / C ++. Aby ich użyć, musisz najpierw zdefiniować, _USE_MATH_DEFINES
a następnie dołączyć cmath
lub math.h
.
3.14
,3.141592
aatan(1) * 4
?