C++标准库<cmath>头文件常用函数最全总结及项目实战

#include <cmath> 用法总结

  • #include <cmath> 是 C++ 标准库中的头文件,提供了一系列用于执行常见数学运算的函数。与 C 语言中的 <math.h> 类似,但它将函数声明放在 std 命名空间中,以更好地与 C++ 的命名空间特性相兼容。使用 cmath 可以在 C++ 程序中进行各种数学计算,包括基本的算术运算、三角函数、指数和对数运算、取整函数等。

是否为标准库

  • #include <cmath> 是 C++ 标准库的一部分,提供了数学计算所需的函数和常量,使用该头文件可以使 C++ 程序更方便地进行数学操作,无需额外的外部库。

cmath 头文件中的所有函数

  • 基本数学运算函数
    • std::abs(double x):计算浮点数 x 的绝对值。
    • std::pow(double x, double y):计算 xy 次幂。
    • std::sqrt(double x):计算 x 的平方根。
    • std::cbrt(double x):计算 x 的立方根。
    • std::hypot(double x, double y):计算直角三角形斜边长度,即 sqrt(x*x + y*y)
  • 三角函数
    • std::sin(double x)std::cos(double x)std::tan(double x):分别计算 x 的正弦、余弦和正切值。
    • std::asin(double x)std::acos(double x)std::atan(double x):分别计算 x 的反正弦、反余弦和反正切值。
    • std::atan2(double y, double x):计算 y/x 的反正切值,考虑了 xy 的符号。
  • 指数和对数函数
    • std::exp(double x):计算自然常数 ex 次幂。
    • std::log(double x):计算 x 的自然对数(以 e 为底)。
    • std::log10(double x):计算 x 的以 10 为底的对数。
    • std::log2(double x):计算 x 的以 2 为底的对数。
  • 舍入和取整函数
    • std::floor(double x):将 x 向下舍入到最接近的整数。
    • std::ceil(double x):将 x 向上舍入到最接近的整数。
    • std::round(double x):将 x 四舍五入到最接近的整数。
    • std::trunc(double x):截断 x 的小数部分,只保留整数部分。
  • 其他函数
    • std::fmod(double x, double y):计算 x 除以 y 的余数。
    • std::fmax(double x, double y):返回 xy 中的最大值。
    • std::fmin(double x, double y):返回 xy 中的最小值。
    • std::remainder(double x, double y):计算 x 除以 y 的 IEEE 754 余数。

cmath 头文件中的函数及代码实例

  • 基本数学运算函数
    • std::abs(double x):计算浮点数 x 的绝对值。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = -5.5;
        std::cout << "The absolute value of " << num << " is " << std::abs(num) << std::endl;
        return 0;
    }
    
    • std::pow(double x, double y):计算 xy 次幂。
    #include <iostream>
    #include <cmath>
    int main() {
        double base = 2.0;
        double exponent = 3.0;
        std::cout << base << " raised to the power of " << exponent << " is " << std::pow(base, exponent) << std::endl;
        return 0;
    }
    
    • std::sqrt(double x):计算 x 的平方根。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 25.0;
        std::cout << "The square root of " << num << " is " << std::sqrt(num) << std::endl;
        return 0;
    }
    
    • std::cbrt(double x):计算 x 的立方根。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 27.0;
        std::cout << "The cube root of " << num << " is " << std::cbrt(num) << std::endl;
        return 0;
    }
    
    • std::hypot(double x, double y):计算直角三角形斜边长度,即 sqrt(x*x + y*y)
    #include <iostream>
    #include <cmath>
    int main() {
        double x = 3.0;
        double y = 4.0;
        std::cout << "The hypotenuse of a right triangle with sides " << x << " and " << y << " is " << std::hypot(x, y) << std::endl;
        return 0;
    }
    
  • 三角函数
    • std::sin(double x)std::cos(double x)std::tan(double x):分别计算 x 的正弦、余弦和正切值。
    #include <iostream>
    #include <cmath>
    int main() {
        double angle = 0.5; // 弧度
        std::cout << "sin(" << angle << ") = " << std::sin(angle) << std::endl;
        std::cout << "cos(" << angle << ") = " << std::cos(angle) << std::endl;
        std::cout << "tan(" << angle << ") = " << std::tan(angle) << std::endl;
        return 0;
    }
    
    • std::asin(double x)std::acos(double x)std::atan(double x):分别计算 x 的反正弦、反余弦和反正切值。
    #include <iostream>
    #include <cmath>
    int main() {
        double value = 0.5;
        std::cout << "asin(" << value << ") = " << std::asin(value) << std::endl;
        std::cout << "acos(" << value << ") = " << std::acos(value) << std::endl;
        std::cout << "atan(" << value << ") = " << std::atan(value) << std::endl;
        return 0;
    }
    
    • std::atan2(double y, double x):计算 y/x 的反正切值,考虑了 xy 的符号。
    #include <iostream>
    #include <cmath>
    int main() {
        double y = 1.0;
        double x = 1.0;
        std::cout << "atan2(" << y << ", " << x << ") = " << std::atan2(y, x) << std::endl;
        return 0;
    }
    
  • 指数和对数函数
    • std::exp(double x):计算自然常数 ex 次幂。
    #include <iostream>
    #include <cmath>
    int main() {
        double exponent = 1.0;
        std::cout << "e raised to the power of " << exponent << " is " << std::exp(exponent) << std::endl;
        return 0;
    }
    
    • std::log(double x):计算 x 的自然对数(以 e 为底)。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = std::exp(1.0);
        std::cout << "The natural logarithm of " << num << " is " << std::log(num) << std::endl;
        return 0;
    }
    
    • std::log10(double x):计算 x 的以 10 为底的对数。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 100.0;
        std::cout << "The base-10 logarithm of " << num << " is " << std::log10(num) << std::endl;
        return 0;
    }
    
    • std::log2(double x):计算 x 的以 2 为底的对数。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 8.0;
        std::cout << "The base-2 logarithm of " << num << " is " << std::log2(num) << std::endl;
        return 0;
    }
    
  • 舍入和取整函数
    • std::floor(double x):将 x 向下舍入到最接近的整数。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 3.7;
        std::cout << "Floor of " << num << " is " << std::floor(num) << std::endl;
        return 0;
    }
    
    • std::ceil(double x):将 x 向上舍入到最接近的整数。
      向上取整是一种数学运算,对于一个浮点数 x,向上取整的结果是大于或等于 x 的最小整数。例如:
  • 如果 x = 3.14,那么 ceilf(x) 的结果是 4
  • 如果 x = 5.0,那么 ceilf(x) 的结果是 5
  • 如果 x = -2.3,那么 ceilf(x) 的结果是 -2

在 C++ 中,ceilf 函数的原型是 float ceilf(float x);,它接受一个单精度浮点数 x 作为输入,并返回一个单精度浮点数,该浮点数是大于或等于 x 的最小整数。

以下是一个代码示例,展示了 ceilf 函数的使用:

#include <iostream>
#include <cmath>

int main() {
    float num1 = 3.14f;
    float num2 = 5.0f;
    float num3 = -2.3f;

    std::cout << "ceilf(" << num1 << ") = " << ceilf(num1) << std::endl;
    std::cout << "ceilf(" << num2 << ") = " << ceilf(num2) << std::endl;
    std::cout << "ceilf(" << num3 << ") = " << ceilf(num3) << std::endl;

    return 0;
}

在这个示例中,我们使用 ceilf 函数对三个不同的浮点数进行向上取整操作,并将结果输出到控制台。

ceilf 函数在许多场景中都很有用,例如:

  • 在计算需要将空间划分为离散块时,如上述将空间划分为体素块的代码中,使用 ceilf 确保能够完全覆盖空间,避免因向下取整而导致部分空间未被划分。
  • 在资源分配问题中,如果要分配一定数量的资源给多个任务,并且每个任务需要至少一个资源,使用向上取整可以确保有足够的资源分配,即使计算结果是小数。

此外,C++ 中还有 ceil 函数,它接受 double 类型的参数,返回 double 类型的结果,使用方式与 ceilf 类似,例如:

#include <iostream>
#include <cmath>

int main() {
    double num = 3.14;
    std::cout << "ceil(" << num << ") = " << ceil(num) << std::endl;
    return 0;
}

如果你使用 ceil 函数,需要包含 cmath 头文件,它遵循相同的向上取整规则,但处理双精度浮点数。对于整数部分是负数的浮点数,向上取整会向 0 的方向取整,即取绝对值较小的整数,例如 ceil(-2.3)-2 而不是 -3

总之,向上取整是一种确保得到的结果是大于或等于原始值的最小整数的操作,在需要将连续的浮点数转换为离散的整数,并且需要覆盖整个范围时非常有用。

  • std::round(double x):将 x 四舍五入到最接近的整数。
  #include <iostream>
  #include <cmath>
  int main() {
      double num = 3.5;
      std::cout << "Round of " << num << " is " << std::round(num) << std::endl;
      return 0;
  }
  • std::trunc(double x):截断 x 的小数部分,只保留整数部分。
    #include <iostream>
    #include <cmath>
    int main() {
        double num = 3.8;
        std::cout << "Trunc of " << num << " is " << std::trunc(num) << std::endl;
        return 0;
    }
    
    • 其他函数
    • std::fmod(double x, double y):计算 x 除以 y 的余数。
    #include <iostream>
    #include <cmath>
    int main() {
        double dividend = 10.0;
        double divisor = 3.0;
        std::cout << dividend << " modulo " << divisor << " is " << std::fmod(dividend, divisor) << std::endl;
        return 0;
    }
    
    • std::fmax(double x, double y):返回 xy 中的最大值。
    #include <iostream>
    #include <cmath>
    int main() {
        double num1 = 5.0;
        double num2 = 10.0;
        std::cout << "The maximum of " << num1 << " and " << num2 << " is " << std::fmax(num1, num2) << std::endl;
        return 0;
    }
    
    • std::fmin(double x, double y):返回 xy 中的最小值。
    #include <iostream>
    #include <cmath>
    int main() {
        double num1 = 5.0;
        double num2 = 10.0;
        std::cout << "The minimum of " << num1 << " and " << num2 << " is " << std::fmin(num1, num2) << std::endl;
        return 0;
    }
    
    • std::remainder(double x, double y):计算 x 除以 y 的 IEEE 754 余数。
    #include <iostream>
    #include <cmath>
    int main() {
        double dividend = 10.0;
        double divisor = 3.0;
        std::cout << dividend << " remainder by " << divisor << " is " << std::remainder(dividend, divisor) << std::endl;
        return 0;
    }
    

机器人 SLAM 方向上的项目实例代码

以下是一个更完整的机器人 SLAM 项目中的代码示例,使用了 cmath 中的多个函数:

#include <iostream>
#include <vector>
#include <cmath>
#include <cmath>
#include <random>

struct Pose {
    double x;
    double y;
    double theta;
};

class RobotSLAM {
public:
    RobotSLAM() : robot_pose{0.0, 0.0, 0.0} {}

    // 模拟机器人运动
    void move(double linear_velocity, double angular_velocity, double time) {
        double delta_theta = angular_velocity * time;
        double distance = linear_velocity * time;
        robot_pose.theta += delta_theta;
        robot_pose.x += distance * std::cos(robot_pose.theta);
        robot_pose.y += distance * std::sin(robot_pose.theta);
    }

    // 模拟激光雷达测量
    std::vector<double> sense() {
        std::vector<double> measurements;
        std::default_random_engine gen;
        std::normal_distribution<double> dist(5.0, 0.5); // 均值为 5,标准差为 0.5 的正态分布
        for (int i = 0; i < 10; ++i) {
            double measurement = dist(gen);
            measurements.push_back(measurement);
        }
        return measurements;
    }

    // 根据测量更新地图
    void updateMap(const std::vector<double>& measurements, double sensor_angle_increment) {
        double angle = robot_pose.theta - M_PI / 2;
        for (const auto& measurement : measurements) {
            double global_x = robot_pose.x + measurement * std::cos(angle);
            double global_y = robot_pose.y + measurement * std::sin(angle);
            map.push_back({global_x, global_y});
            angle += sensor_angle_increment;
        }
    }

    // 打印地图
    void printMap() const {
        for (const auto& point : map) {
            std::cout << "Point: (" << point.x << ", " << point.y << ")" << std::endl;
        }
    }

private:
    Pose robot_pose;
    std::vector<Pose> map;
};

int main() {
    RobotSLAM slam;
    double linear_velocity = 0.5; // 线速度
    double angular_velocity = 0.1; // 角速度
    double time_step = 1.0; // 时间步长
    double sensor_angle_increment = M_PI / 5; // 激光雷达角度增量

    for (int i = 0; i < 5; ++i) {
        slam.move(linear_velocity, angular_velocity, time_step);
        auto measurements = slam.sense();
        slam.updateMap(measurements, sensor_angle_increment);
    }
    slam.printMap();
    return 0;
}

代码解释

  • 定义了 Pose 结构体来表示机器人的位置和朝向。
  • RobotSLAM 类包含机器人的当前 Pose 以及存储地图的 map 向量。
    • move 函数根据线速度和角速度更新机器人的位置和朝向,使用 std::cosstd::sin 函数将线速度转换为 xy 方向的位移。
    • sense 函数模拟激光雷达的测量,使用 std::normal_distribution 生成带有噪声的测量值。
    • updateMap 函数根据测量更新地图,将测量点转换为全局坐标,这里使用 std::cosstd::sin 函数根据角度和测量距离计算全局坐标。
    • printMap 函数打印地图中的所有点。

main 函数中,模拟了机器人的运动和测量更新,使用 cmath 中的函数完成机器人的运动学计算和测量点的坐标转换,逐步构建环境地图。这个例子展示了 cmath 在机器人 SLAM 中用于位置更新、传感器测量和地图构建等方面的综合应用,这些函数为机器人的运动和环境感知提供了必要的数学计算支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行知SLAM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值