C++ 标准库  complex

以下对 C++ 标准库中 <complex> 头文件所提供的复数类型与相关函数做一次系统、深入的梳理,包括类型定义、成员函数、全局操作、转换与输入/输出示例,以及实践建议。


一、概述

  • <complex> 定义了一个模板类 std::complex<T>,用于表示实部和虚部均为浮点类型 T(通常为 floatdouble 或 long double)的复数。
  • 除了对复数进行基本算术运算外,还提供了绝对值、相位、指数/对数、三角与双曲函数、共轭等一系列数学函数。
  • 所有操作均在复数数学的框架下进行,且在不同精度类型间具有良好的模板通用性。

二、std::complex<T> 类模板

template< class T >
class complex {
public:
    // ——— 构造与赋值 ———
    constexpr complex( const T& re = T(), const T& im = T() );
    template<class U> constexpr complex( const complex<U>& );

    // ——— 访问成员 ———
    constexpr T real() const;            // 实部
    constexpr T imag() const;            // 虚部
    void      real( const T& value );   // 设定实部
    void      imag( const T& value );   // 设定虚部

    // ——— 运算符重载 ———
    complex& operator+=( const complex& );
    complex& operator-=( const complex& );
    complex& operator*=( const complex& );
    complex& operator/=( const complex& );
};
  • 构造
    • complex<> c; 构造 0+0i
    • complex<> c(3.0,4.0); 构造 3+4i
    • 支持不同精度的隐式拷贝,如 complex<double> cd = complex<float>(1.0f,2.0f);
  • 成员访问
    • c.real() / c.imag() 分别返回实部和虚部
    • 可通过 c.real(5.0) 修改实部
  • 复合赋值
    • c1 += c2 等效于 c1 = c1 + c2,其余 -=*=/= 类似

三、全局算术与比较运算符

// 二元算术
template<class T> complex<T> operator+( const complex<T>&, const complex<T>& );
template<class T> complex<T> operator-( ... );
template<class T> complex<T> operator*( ... );
template<class T> complex<T> operator/( ... );

// 复数与实数混合运算
template<class T> complex<T> operator+( const complex<T>&, const T& );
template<class T> complex<T> operator+( const T&, const complex<T>& );
// 其它 -,*,/ 同理

// 一元运算
template<class T> complex<T> operator-( const complex<T>& );  // 取负

// 比较(C++20 起)
template<class T> bool operator==( const complex<T>&, const complex<T>& );
template<class T> bool operator!=( ... );
  • 所有运算遵循复数四则规则,如(a+bi)×(c+di)=(ac−bd)  +  (ad+bc) i
  • 注意:旧标准中未定义复数比较运算;C++20 起可直接用 ==/!= 比较实部和虚部是否分别相等。

四、常用数学函数

1. 基本函数

函数描述
std::conj(z)共轭:实部不变,虚部取反
std::real(z) / std::imag(z)非成员版访问实部/虚部
std::abs(z)复数模长 a2+b2
std::arg(z)复数幅角 \atan2(b,a)
std::norm(z)模长平方 a2+b2(返回实数类型)
std::proj(z) (C++11+)投影到 Riemann 球面,处理无穷大和 NaN 情形

2. 指数与对数

函数描述
std::exp(z)复指数函数 ez
std::log(z)自然对数 ln⁡z
std::log10(z)常用对数 log⁡10z
std::pow(z, w)幂运算 zw

3. 三角与双曲函数

函数描述
std::sin(z) / std::cos(z)正弦 / 余弦
std::tan(z)正切
std::sinh(z) / std::cosh(z)双曲正弦 / 双曲余弦
std::tanh(z)双曲正切
反函数:std::asin(z)acos(z)atan(z)asinh(z) 等同理

五、输入/输出支持

#include <complex>
#include <iostream>

int main() {
    std::complex<double> z;
    std::cin  >> z;   // 从输入流读取两数,格式:real imag
    std::cout << z;   // 输出格式: (real,imag)
}
  • 格式化
    • 默认输出形如 (a,b),其中 a 为实部,b 为虚部
    • 读取时,会消费括号及逗号,可与流操纵符组合控制格式

六、示例:综合运用

#include <complex>
#include <iostream>
#include <vector>
#include <numeric>

int main() {
    // 构造一个复数向量
    std::vector<std::complex<double>> v;
    for (int k = 0; k < 8; ++k) {
        // 生成单位圆上等分点
        double theta = 2.0 * M_PI * k / 8;
        v.emplace_back(std::polar(1.0, theta));  
    }

    // 计算所有共轭之和
    auto conj_sum = std::accumulate(
        v.begin(), v.end(),
        std::complex<double>{0,0},
        [](auto a, auto b){ return a + std::conj(b); }
    );

    std::cout << "Sum of conjugates: " << conj_sum << "\n";

    // 计算第一个元素的模长与幅角
    auto z0 = v.front();
    std::cout << "abs = " << std::abs(z0)
              << ", arg = " << std::arg(z0) << "\n";
}
  • std::polar(r, θ):根据极坐标构造复数 r  (cos⁡θ+isin⁡θ)
  • 利用 <numeric> 中的 std::accumulatestd::conj 等函数完成批量运算

七、实践建议

  1. 选择合适的底层类型
    • 对于标准科学计算,double 足够;对高精度或数值稳定性要求极高场景可考虑 long double
  2. 注意数值稳定性
    • std::norm 而非 std::abs 平方:前者避免一次开方,若只需模长平方推荐用 norm
    • 当实部或虚部远大于另一分量时,std::abs 可能出现溢出/下溢,可考虑手动缩放或专门算法。
  3. 使用 std::polar / std::arg 完成极坐标转换
    • 在信号处理、频域分析(如 FFT)中,经常需要从直角坐标与极坐标互转。
  4. 避免不必要的临时对象
    • 复数表达式可能产生临时,多层链式运算时注意编译器优化。
    • 对性能敏感环节,可使用 operator+= 等复合赋值减少拷贝。
  5. 结合并行与向量化
    • C++17 起可将复数容器与并行算法(std::for_each(std::execution::par,…))结合,加速批量运算;但要确保函数无数据竞争。

通过以上对 <complex> 头文件中 std::complex 模板、算术运算、数学函数与 I/O 支持的全面讲解,希冀帮助你在数值计算、信号处理、物理建模等领域高效、正确地使用标准库复数功能。祝编码顺利!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注