C++ 数字与数值
概述
数字和数值运算是编程的基础。C++提供了丰富的数值类型和数学函数库,支持从基本的算术运算到复杂的数学计算。本章将介绍数值类型、数学运算、精度处理以及相关的最佳实践。
🔢 数值类型概览
整数类型范围
cpp
#include <iostream>
#include <climits>
int main() {
std::cout << "=== 整数类型范围 ===" << std::endl;
// 有符号整数类型
std::cout << "char: " << (int)CHAR_MIN << " 到 " << (int)CHAR_MAX << std::endl;
std::cout << "short: " << SHRT_MIN << " 到 " << SHRT_MAX << std::endl;
std::cout << "int: " << INT_MIN << " 到 " << INT_MAX << std::endl;
std::cout << "long long: " << LLONG_MIN << " 到 " << LLONG_MAX << std::endl;
// 无符号整数类型
std::cout << "\n无符号类型最大值:" << std::endl;
std::cout << "unsigned int: " << UINT_MAX << std::endl;
std::cout << "unsigned long long: " << ULLONG_MAX << std::endl;
// 类型大小
std::cout << "\n类型大小(字节):" << std::endl;
std::cout << "int: " << sizeof(int) << std::endl;
std::cout << "long: " << sizeof(long) << std::endl;
std::cout << "long long: " << sizeof(long long) << std::endl;
return 0;
}浮点类型特性
cpp
#include <iostream>
#include <cfloat>
#include <iomanip>
int main() {
std::cout << "=== 浮点类型特性 ===" << std::endl;
// 精度位数
std::cout << "float 精度: " << FLT_DIG << " 位" << std::endl;
std::cout << "double 精度: " << DBL_DIG << " 位" << std::endl;
// 类型大小
std::cout << "float: " << sizeof(float) << " 字节" << std::endl;
std::cout << "double: " << sizeof(double) << " 字节" << std::endl;
// 精度演示
std::cout << "\n=== 精度演示 ===" << std::endl;
float f = 1.23456789f;
double d = 1.23456789;
std::cout << std::setprecision(10);
std::cout << "float: " << f << std::endl;
std::cout << "double: " << d << std::endl;
return 0;
}➕ 基本数学运算
算术运算符
cpp
#include <iostream>
int main() {
std::cout << "=== 基本算术运算 ===" << std::endl;
int a = 15, b = 4;
double x = 15.0, y = 4.0;
// 整数运算
std::cout << "整数运算 (a=" << a << ", b=" << b << "):" << std::endl;
std::cout << "a + b = " << (a + b) << std::endl;
std::cout << "a - b = " << (a - b) << std::endl;
std::cout << "a * b = " << (a * b) << std::endl;
std::cout << "a / b = " << (a / b) << " (整数除法)" << std::endl;
std::cout << "a % b = " << (a % b) << " (取余)" << std::endl;
// 浮点运算
std::cout << "\n浮点运算 (x=" << x << ", y=" << y << "):" << std::endl;
std::cout << "x / y = " << (x / y) << " (浮点除法)" << std::endl;
// 复合赋值运算符
std::cout << "\n=== 复合赋值运算符 ===" << std::endl;
int num = 10;
std::cout << "初始值: " << num << std::endl;
num += 5; std::cout << "num += 5: " << num << std::endl;
num -= 3; std::cout << "num -= 3: " << num << std::endl;
num *= 2; std::cout << "num *= 2: " << num << std::endl;
num /= 4; std::cout << "num /= 4: " << num << std::endl;
// 自增自减
std::cout << "\n=== 自增自减运算符 ===" << std::endl;
int i = 5;
std::cout << "i++ = " << i++ << " (后自增)" << std::endl;
std::cout << "++i = " << ++i << " (前自增)" << std::endl;
return 0;
}数学函数库
cpp
#include <iostream>
#include <cmath>
#include <iomanip>
int main() {
std::cout << std::fixed << std::setprecision(4);
std::cout << "=== 基本数学函数 ===" << std::endl;
double num = 16.0;
std::cout << "sqrt(16): " << sqrt(num) << std::endl;
std::cout << "pow(2, 4): " << pow(2, 4) << std::endl;
std::cout << "exp(1): " << exp(1) << std::endl;
std::cout << "log(10): " << log(10) << std::endl;
std::cout << "\n=== 三角函数 ===" << std::endl;
double angle = M_PI / 4; // 45度
std::cout << "sin(π/4): " << sin(angle) << std::endl;
std::cout << "cos(π/4): " << cos(angle) << std::endl;
std::cout << "tan(π/4): " << tan(angle) << std::endl;
std::cout << "\n=== 取整函数 ===" << std::endl;
double decimal = 3.7;
std::cout << "原值: " << decimal << std::endl;
std::cout << "ceil: " << ceil(decimal) << std::endl;
std::cout << "floor: " << floor(decimal) << std::endl;
std::cout << "round: " << round(decimal) << std::endl;
std::cout << "\n=== 其他函数 ===" << std::endl;
std::cout << "abs(-5): " << abs(-5) << std::endl;
std::cout << "fabs(-5.5): " << fabs(-5.5) << std::endl;
std::cout << "fmod(7.5, 2.5): " << fmod(7.5, 2.5) << std::endl;
return 0;
}🎯 数值精度和比较
浮点精度问题
cpp
#include <iostream>
#include <iomanip>
#include <cmath>
int main() {
std::cout << std::fixed << std::setprecision(20);
std::cout << "=== 浮点精度问题 ===" << std::endl;
// 典型的浮点精度问题
double a = 0.1;
double b = 0.2;
double sum = a + b;
std::cout << "0.1 + 0.2 = " << sum << std::endl;
std::cout << "是否等于0.3? " << (sum == 0.3 ? "是" : "否") << std::endl;
// 安全的浮点比较
std::cout << "\n=== 安全的浮点比较 ===" << std::endl;
auto isEqual = [](double x, double y, double epsilon = 1e-9) {
return std::abs(x - y) < epsilon;
};
std::cout << "使用epsilon比较:" << std::endl;
std::cout << "0.1 + 0.2 ≈ 0.3? " << (isEqual(sum, 0.3) ? "是" : "否") << std::endl;
return 0;
}舍入和格式化
cpp
#include <iostream>
#include <iomanip>
#include <cmath>
// 自定义舍入函数
double roundToDecimalPlaces(double value, int decimalPlaces) {
double factor = std::pow(10.0, decimalPlaces);
return std::round(value * factor) / factor;
}
int main() {
std::cout << std::fixed;
std::cout << "=== 舍入方法 ===" << std::endl;
double value = 2.675;
std::cout << std::setprecision(3) << "原值: " << value << std::endl;
std::cout << std::setprecision(2);
std::cout << "四舍五入到2位: " << roundToDecimalPlaces(value, 2) << std::endl;
std::cout << "向上取整: " << std::ceil(value * 100) / 100 << std::endl;
std::cout << "向下取整: " << std::floor(value * 100) / 100 << std::endl;
std::cout << "\n=== 格式化输出 ===" << std::endl;
double pi = 3.141592653589793;
std::cout << "2位小数: " << std::setprecision(2) << pi << std::endl;
std::cout << "4位小数: " << std::setprecision(4) << pi << std::endl;
std::cout << "科学记数法: " << std::scientific << pi << std::endl;
return 0;
}🔀 数值转换
类型转换和字符串转换
cpp
#include <iostream>
#include <string>
int main() {
std::cout << "=== 数值类型转换 ===" << std::endl;
// 隐式转换
int i = 42;
double d = i; // int to double (安全)
std::cout << "int到double: " << i << " -> " << d << std::endl;
double d2 = 3.14159;
int i2 = static_cast<int>(d2); // 显式转换
std::cout << "double到int: " << d2 << " -> " << i2 << std::endl;
// 字符串转换
std::cout << "\n=== 字符串转换 ===" << std::endl;
// 数值到字符串
int num = 123;
double decimal = 45.67;
std::string str1 = std::to_string(num);
std::string str2 = std::to_string(decimal);
std::cout << "to_string: " << num << " -> \"" << str1 << "\"" << std::endl;
std::cout << "to_string: " << decimal << " -> \"" << str2 << "\"" << std::endl;
// 字符串到数值
std::string strNum = "987";
std::string strDecimal = "12.34";
try {
int converted1 = std::stoi(strNum);
double converted2 = std::stod(strDecimal);
std::cout << "stoi: \"" << strNum << "\" -> " << converted1 << std::endl;
std::cout << "stod: \"" << strDecimal << "\" -> " << converted2 << std::endl;
}
catch (const std::exception& e) {
std::cout << "转换错误: " << e.what() << std::endl;
}
return 0;
}🎲 随机数生成
现代C++随机数
cpp
#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
int main() {
std::cout << "=== 现代C++随机数生成 ===" << std::endl;
// 随机数引擎
std::random_device rd; // 硬件随机数
std::mt19937 gen(rd()); // Mersenne Twister生成器
// 均匀整数分布
std::cout << "=== 均匀整数分布 (1-10) ===" << std::endl;
std::uniform_int_distribution<> intDist(1, 10);
for (int i = 0; i < 10; i++) {
std::cout << intDist(gen) << " ";
}
std::cout << std::endl;
// 均匀实数分布
std::cout << "\n=== 均匀实数分布 (0.0-1.0) ===" << std::endl;
std::uniform_real_distribution<> realDist(0.0, 1.0);
for (int i = 0; i < 5; i++) {
std::cout << std::fixed << std::setprecision(4) << realDist(gen) << " ";
}
std::cout << std::endl;
// 随机洗牌
std::cout << "\n=== 随机洗牌 ===" << std::endl;
std::vector<int> deck = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << "原始: ";
for (int card : deck) std::cout << card << " ";
std::cout << std::endl;
std::shuffle(deck.begin(), deck.end(), gen);
std::cout << "洗牌后: ";
for (int card : deck) std::cout << card << " ";
std::cout << std::endl;
return 0;
}随机数应用示例
cpp
#include <iostream>
#include <random>
#include <map>
// 随机数工具类
class RandomUtils {
private:
std::mt19937 gen_;
public:
RandomUtils() : gen_(std::random_device{}()) {}
int randomInt(int min, int max) {
std::uniform_int_distribution<> dist(min, max);
return dist(gen_);
}
double randomReal(double min, double max) {
std::uniform_real_distribution<> dist(min, max);
return dist(gen_);
}
bool randomBool(double probability = 0.5) {
std::bernoulli_distribution dist(probability);
return dist(gen_);
}
};
int main() {
RandomUtils random;
std::cout << "=== 随机数应用示例 ===" << std::endl;
// 模拟骰子
std::cout << "=== 模拟投掷骰子 ===" << std::endl;
std::map<int, int> diceResults;
for (int i = 0; i < 600; i++) {
int roll = random.randomInt(1, 6);
diceResults[roll]++;
}
for (const auto& [face, count] : diceResults) {
std::cout << "点数 " << face << ": " << count << " 次" << std::endl;
}
// 概率事件
std::cout << "\n=== 概率事件模拟 ===" << std::endl;
int successCount = 0;
int trials = 1000;
double successProbability = 0.3;
for (int i = 0; i < trials; i++) {
if (random.randomBool(successProbability)) {
successCount++;
}
}
double actualProbability = static_cast<double>(successCount) / trials;
std::cout << "期望概率: " << successProbability << std::endl;
std::cout << "实际概率: " << actualProbability << std::endl;
return 0;
}📊 数值计算示例
简单数值算法
cpp
#include <iostream>
#include <cmath>
#include <vector>
// 计算平均值
double calculateMean(const std::vector<double>& data) {
double sum = 0.0;
for (double value : data) {
sum += value;
}
return sum / data.size();
}
// 计算标准差
double calculateStandardDeviation(const std::vector<double>& data) {
double mean = calculateMean(data);
double sumSquaredDiff = 0.0;
for (double value : data) {
double diff = value - mean;
sumSquaredDiff += diff * diff;
}
return std::sqrt(sumSquaredDiff / data.size());
}
// 查找最大值和最小值
std::pair<double, double> findMinMax(const std::vector<double>& data) {
double minVal = data[0];
double maxVal = data[0];
for (double value : data) {
if (value < minVal) minVal = value;
if (value > maxVal) maxVal = value;
}
return {minVal, maxVal};
}
int main() {
std::cout << "=== 数值计算示例 ===" << std::endl;
std::vector<double> data = {1.2, 3.4, 2.1, 4.8, 2.9, 3.7, 1.8, 4.2, 3.1, 2.6};
std::cout << "数据: ";
for (double value : data) {
std::cout << value << " ";
}
std::cout << std::endl;
// 统计计算
double mean = calculateMean(data);
double stdDev = calculateStandardDeviation(data);
auto [minVal, maxVal] = findMinMax(data);
std::cout << std::fixed << std::setprecision(3);
std::cout << "平均值: " << mean << std::endl;
std::cout << "标准差: " << stdDev << std::endl;
std::cout << "最小值: " << minVal << std::endl;
std::cout << "最大值: " << maxVal << std::endl;
std::cout << "范围: " << (maxVal - minVal) << std::endl;
return 0;
}📋 数值处理最佳实践
数值编程指南
cpp
#include <iostream>
#include <limits>
#include <cmath>
int main() {
std::cout << "=== 数值编程最佳实践 ===" << std::endl;
// 1. 避免除零错误
auto safeDivide = [](double a, double b) -> double {
if (std::abs(b) < std::numeric_limits<double>::epsilon()) {
std::cout << "警告:除数接近零" << std::endl;
return std::numeric_limits<double>::infinity();
}
return a / b;
};
std::cout << "10 / 2 = " << safeDivide(10.0, 2.0) << std::endl;
std::cout << "10 / 0 = " << safeDivide(10.0, 0.0) << std::endl;
// 2. 使用合适的数据类型
std::cout << "\n=== 选择合适的数据类型 ===" << std::endl;
// 计数用int
int count = 0;
// 大整数用long long
long long bigNumber = 1234567890123456LL;
// 精确计算用double
double precision = 0.123456789;
// 内存敏感场景用float
float memory_efficient = 3.14f;
std::cout << "count: " << count << std::endl;
std::cout << "bigNumber: " << bigNumber << std::endl;
std::cout << "precision: " << precision << std::endl;
std::cout << "memory_efficient: " << memory_efficient << std::endl;
// 3. 处理溢出
std::cout << "\n=== 溢出检查 ===" << std::endl;
auto safeMultiply = [](int a, int b) -> long long {
long long result = static_cast<long long>(a) * b;
if (result > std::numeric_limits<int>::max()) {
std::cout << "警告:整数溢出" << std::endl;
}
return result;
};
std::cout << "100000 * 50000 = " << safeMultiply(100000, 50000) << std::endl;
return 0;
}总结
C++提供了强大的数值处理能力,从基本运算到复杂的数学计算:
核心要点
- 数值类型:选择合适的整数和浮点类型
- 数学函数:利用
<cmath>库进行数学运算 - 精度处理:注意浮点数精度和比较方法
- 类型转换:掌握数值和字符串之间的转换
- 随机数:使用现代C++的随机数生成器
最佳实践
- 使用epsilon进行浮点数比较
- 选择合适的数据类型避免溢出
- 进行输入验证防止运算错误
- 使用标准库函数而非自己实现
- 注意数值计算的精度和性能
良好的数值处理技能是科学计算、图形学、游戏开发等领域的基础。