跳到主要内容

C++ 数值操作

引言

在C++编程中,数值操作是一个非常重要的方面,尤其是在科学计算、统计分析、金融模型和游戏开发等领域。C++ STL (标准模板库) 提供了丰富的数值算法和功能,让开发者能够高效地进行各种数值计算。本文将介绍C++ STL中的数值操作功能,这些功能主要在<numeric><cmath>头文件中定义。

提示

数值操作是C++ STL的重要组成部分,掌握这些操作可以大大提高处理数值数据的效率和准确性。

基础数值算法

accumulate - 计算累加值

accumulate函数用于计算给定范围内所有元素的总和。

cpp
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

// 计算总和
int sum = std::accumulate(numbers.begin(), numbers.end(), 0);

std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 15

// 使用自定义二元操作 - 计算乘积
int product = std::accumulate(numbers.begin(), numbers.end(), 1,
std::multiplies<int>());

std::cout << "Product: " << product << std::endl; // 输出: Product: 120

return 0;
}

partial_sum - 计算部分和

partial_sum函数计算一个序列的连续部分和,并将结果保存到另一个序列中。

cpp
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::vector<int> result(numbers.size());

std::partial_sum(numbers.begin(), numbers.end(), result.begin());

std::cout << "Partial sums: ";
for (int num : result) {
std::cout << num << " "; // 输出: 1 3 6 10 15
}
std::cout << std::endl;

return 0;
}

inner_product - 计算内积

inner_product函数计算两个序列的内积(点积)。

cpp
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};

int result = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);

std::cout << "Inner product: " << result << std::endl; // 输出: Inner product: 32 (1*4 + 2*5 + 3*6)

return 0;
}

adjacent_difference - 计算相邻元素之间的差

adjacent_difference函数计算序列中相邻元素之间的差,并将结果保存到另一个序列中。

cpp
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> numbers = {1, 3, 6, 10, 15};
std::vector<int> result(numbers.size());

std::adjacent_difference(numbers.begin(), numbers.end(), result.begin());

std::cout << "Adjacent differences: ";
for (int num : result) {
std::cout << num << " "; // 输出: 1 2 3 4 5
}
std::cout << std::endl;

return 0;
}

数值类型转换

iota - 填充递增序列

iota函数用连续递增的值填充一个范围。

cpp
#include <iostream>
#include <vector>
#include <numeric>

int main() {
std::vector<int> numbers(5);

std::iota(numbers.begin(), numbers.end(), 10);

std::cout << "Sequence: ";
for (int num : numbers) {
std::cout << num << " "; // 输出: 10 11 12 13 14
}
std::cout << std::endl;

return 0;
}

随机数生成

C++11 引入了强大的随机数生成工具,位于<random>头文件中。

基本随机数生成

cpp
#include <iostream>
#include <random>
#include <ctime>

int main() {
// 创建随机数生成器
std::mt19937 generator(std::time(0)); // 使用当前时间作为种子

// 创建均匀分布
std::uniform_int_distribution<int> distribution(1, 100);

// 生成随机数
for (int i = 0; i < 5; ++i) {
std::cout << "Random number: " << distribution(generator) << std::endl;
}

return 0;
}

不同的分布类型

C++提供了多种分布类型:

cpp
#include <iostream>
#include <random>
#include <ctime>

int main() {
std::mt19937 generator(std::time(0));

// 均匀整数分布
std::uniform_int_distribution<int> uniform_int(1, 6);
std::cout << "Uniform int (dice): " << uniform_int(generator) << std::endl;

// 均匀实数分布
std::uniform_real_distribution<double> uniform_real(0.0, 1.0);
std::cout << "Uniform real: " << uniform_real(generator) << std::endl;

// 正态分布
std::normal_distribution<double> normal(10.0, 2.0); // 均值 = 10.0, 标准差 = 2.0
std::cout << "Normal distribution: " << normal(generator) << std::endl;

// 伯努利分布
std::bernoulli_distribution bernoulli(0.75); // 概率 = 0.75
std::cout << "Bernoulli (75% true): " << bernoulli(generator) << std::endl;

return 0;
}

数学函数

<cmath>头文件提供了各种数学函数。下面是一些常用函数的示例:

cpp
#include <iostream>
#include <cmath>

int main() {
// 绝对值
std::cout << "abs(-5): " << std::abs(-5) << std::endl;

// 幂函数
std::cout << "pow(2, 3): " << std::pow(2, 3) << std::endl;

// 平方根
std::cout << "sqrt(16): " << std::sqrt(16) << std::endl;

// 三角函数 (参数为弧度)
std::cout << "sin(M_PI/2): " << std::sin(M_PI/2) << std::endl;
std::cout << "cos(M_PI): " << std::cos(M_PI) << std::endl;
std::cout << "tan(M_PI/4): " << std::tan(M_PI/4) << std::endl;

// 对数函数
std::cout << "log(10): " << std::log(10) << std::endl; // 自然对数
std::cout << "log10(100): " << std::log10(100) << std::endl; // 以10为底的对数

// 四舍五入
std::cout << "round(3.7): " << std::round(3.7) << std::endl;
std::cout << "floor(3.7): " << std::floor(3.7) << std::endl;
std::cout << "ceil(3.2): " << std::ceil(3.2) << std::endl;

return 0;
}

复数

C++提供了对复数的支持,通过<complex>头文件:

cpp
#include <iostream>
#include <complex>

int main() {
std::complex<double> c1(3.0, 4.0); // 实部 = 3.0, 虚部 = 4.0
std::complex<double> c2(1.0, 2.0);

std::cout << "c1: " << c1 << std::endl;
std::cout << "c2: " << c2 << std::endl;

// 复数运算
std::cout << "c1 + c2: " << (c1 + c2) << std::endl;
std::cout << "c1 - c2: " << (c1 - c2) << std::endl;
std::cout << "c1 * c2: " << (c1 * c2) << std::endl;
std::cout << "c1 / c2: " << (c1 / c2) << std::endl;

// 复数的模和辐角
std::cout << "Magnitude of c1: " << std::abs(c1) << std::endl;
std::cout << "Argument of c1: " << std::arg(c1) << " radians" << std::endl;

// 实部和虚部
std::cout << "Real part of c1: " << std::real(c1) << std::endl;
std::cout << "Imaginary part of c1: " << std::imag(c1) << std::endl;

// 复数的共轭
std::cout << "Complex conjugate of c1: " << std::conj(c1) << std::endl;

return 0;
}

实际应用案例

案例1:简单的统计计算

cpp
#include <iostream>
#include <vector>
#include <numeric>
#include <cmath>
#include <algorithm>

double mean(const std::vector<double>& data) {
return std::accumulate(data.begin(), data.end(), 0.0) / data.size();
}

double variance(const std::vector<double>& data) {
double m = mean(data);
double accum = 0.0;
for (double d : data) {
accum += (d - m) * (d - m);
}
return accum / data.size();
}

double standard_deviation(const std::vector<double>& data) {
return std::sqrt(variance(data));
}

int main() {
std::vector<double> temperatures = {22.5, 23.1, 24.0, 23.4, 22.9, 23.8, 24.5};

std::cout << "Temperature data: ";
for (double t : temperatures) {
std::cout << t << " ";
}
std::cout << std::endl;

std::cout << "Mean: " << mean(temperatures) << std::endl;
std::cout << "Variance: " << variance(temperatures) << std::endl;
std::cout << "Standard Deviation: " << standard_deviation(temperatures) << std::endl;
std::cout << "Min Temperature: " << *std::min_element(temperatures.begin(), temperatures.end()) << std::endl;
std::cout << "Max Temperature: " << *std::max_element(temperatures.begin(), temperatures.end()) << std::endl;

return 0;
}

案例2:蒙特卡洛方法计算π值

cpp
#include <iostream>
#include <random>
#include <ctime>
#include <iomanip>

double estimate_pi(int num_points) {
std::mt19937 generator(std::time(0));
std::uniform_real_distribution<double> distribution(0.0, 1.0);

int points_inside_circle = 0;

for (int i = 0; i < num_points; ++i) {
double x = distribution(generator);
double y = distribution(generator);

// 检查点(x,y)是否在单位圆内
if (x*x + y*y <= 1.0) {
points_inside_circle++;
}
}

// 单位圆在第一象限的面积为π/4
// 因此π ≈ 4 * (点落在圆内的数量) / (总点数)
return 4.0 * points_inside_circle / num_points;
}

int main() {
int num_points = 1000000;
double pi_estimate = estimate_pi(num_points);

std::cout << "使用蒙特卡洛方法估计π (使用 " << num_points << " 个点): "
<< std::setprecision(10) << pi_estimate << std::endl;
std::cout << "实际π值: " << std::setprecision(10) << M_PI << std::endl;

return 0;
}

总结

C++提供了丰富的数值操作工具,帮助开发者进行各种数值计算:

  1. 基础数值算法accumulatepartial_suminner_productadjacent_difference等函数提供基本的数值计算能力。

  2. 数值类型转换iota函数可以生成连续递增的序列。

  3. 随机数生成:C++11引入的<random>库提供了强大的随机数生成功能,支持多种分布类型。

  4. 数学函数<cmath>头文件包含了大量数学函数,如三角函数、指数和对数函数等。

  5. 复数支持:通过<complex>头文件,C++提供了对复数的原生支持。

通过掌握这些工具,开发者可以在C++中进行高效的数值计算,而无需依赖外部库。

练习

  1. 使用accumulate编写一个函数,计算给定向量中所有偶数的总和。
  2. 使用随机数生成器创建一个简单的骰子模拟程序,掷骰子1000次并统计每个点数出现的频率。
  3. 实现一个简单的线性回归计算器,使用inner_product等函数计算斜率和截距。
  4. 编写一个程序,使用<complex>头文件解决二次方程。
  5. 使用蒙特卡洛方法计算一个不规则形状的面积。
备注

学习数值操作是科学计算和算法开发的重要基础。尝试将这些工具应用到您感兴趣的实际问题中,以加深理解。