C/C++数值计算时常需要用到诸如Pi、自然常数e等数学常量,但是这些常量并没有在标准C/C++中定义。幸运的是,现代化的C/C++ math.h 都定义了如下常用的数学常量:

符号 表达式
M_E e 2.71828182845904523536
M_LOG2E log2(e) 1.44269504088896340736
M_LOG10E log10(e) 0.434294481903251827651
M_LN2 ln(2) 0.693147180559945309417
M_LN10 ln(10) 2.30258509299404568402
M_PI pi 3.14159265358979323846
M_PI_2 pi/2 1.57079632679489661923
M_PI_4 pi/4 0.785398163397448309616
M_1_PI 1/pi 0.318309886183790671538
M_2_PI 2/pi 0.636619772367581343076
M_2_SQRTPI 2/sqrt(pi) 1.12837916709551257390
M_SQRT2 sqrt(2) 1.41421356237309504880
M_SQRT1_2 1/sqrt(2) 0.707106781186547524401

需要注意的是,Windows平台上的MSVC编译器,使用这些数学常量需要先定义 _USE_MATH_DEFINES 宏,否则会报未定义的错误:

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

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

到了C++20,事情有了新的变化:新增的 numbers 头文件将这些常量都定义了,并且无需以 M_ 修饰。得益于C++ 14中新增的 变量模板 特性,这些数学常量都以模板的形式定义:

#include <iostream>
#include <iomanip>
#include <numbers>
#include <limits>

int main() {
  // 输出单精度的pi
  std::cout << "float pi: " << std::setprecision(std::numeric_limits<float>::digits10) << std::numbers::pi_v<float> << std::endl;
  // std::numbers::pi 是double类型的特化
  // std::numbers::pi 等同于 std::numbers::pi_v<double>
  std::cout << "double pi: " << std::setprecision(std::numeric_limits<double>::digits10) << std::numbers::pi << std::endl;

  // 双精度的ln(2)
  std::cout << "double ln2: " << std::numbers::ln2 << std::endl;
  return 0;
}

至此,我们可以放心地使用数学常量而无需担心跨平台问题了。

参考

1. Math constants

2. Predefined Mathematical Constants

3. Mathematical constants

4. C++模板编程