004 C++的浮点类型(Floating-Point Types)


作者Lou Xiao, deepseek创建时间2025-04-02 06:55:53更新时间2025-04-02 06:55:53

1 浮点类型概述

1.1 基本概念

  • 浮点类型用于表示实数(带小数点的数)
  • 在C++中有三种基本浮点类型:float, double, long double
  • 遵循IEEE 754标准(大多数现代系统)

1.2 浮点类型特性

类型字节大小(典型)精度(十进制位数)范围(典型)后缀
float4字节6-9位±1.18×10⁻³⁸ to ±3.4×10³⁸f或F
double8字节15-17位±2.23×10⁻³⁰⁸ to ±1.8×10³⁰⁸无或l/L
long double8-16字节18-36位范围更大L

1.3 浮点字面量

类型后缀示例说明
floatf/F3.14f, 1.0e-5F单精度浮点数
double3.14, 1.0e-5双精度浮点数
long doublel/L3.14L, 1.0e-5L扩展精度浮点数

浮点表示形式
- 十进制小数:3.14159
- 科学计数法:6.022e23 (6.022×10²³)
- 十六进制浮点(C++17):0x1.2p3 (1.125×2³=9.0)

1.4 浮点特性(<limits>

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <limits>
2 #include <iostream>
3
4 int main() {
5 std::cout << "float范围: "
6 << std::numeric_limits<float>::min() << " 到 "
7 << std::numeric_limits<float>::max() << '\n';
8
9 std::cout << "float精度位数: "
10 << std::numeric_limits<float>::digits10 << '\n';
11
12 std::cout << "float epsilon: "
13 << std::numeric_limits<float>::epsilon() << '\n';
14
15 return 0;
16 }

2 浮点类型声明与初始化

2.1 声明方式

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 float f; // 声明一个float变量
2 double d; // 声明一个double变量
3 long double ld; // 声明一个long double变量

2.2 初始化方式

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 float f1 = 3.14f; // 使用f后缀表示float
2 double d1 = 3.14; // 默认是double
3 long double ld1 = 3.14L;// 使用L后缀表示long double
4
5 // 科学计数法表示
6 double d2 = 1.23e5; // 1.23 × 10^5
7 float f2 = 1.23e-5f; // 1.23 × 10^-5

三、浮点类型特性详解

3.1 精度问题

  • 浮点数在内存中以二进制形式存储,不能精确表示所有十进制小数
  • 示例:
    cpp double d = 0.1 + 0.2; // 结果可能不是精确的0.3
  • 比较浮点数应使用容差比较而非直接相等比较

3.2 浮点特殊值

值/宏描述示例
INFINITY正无穷大1.0/0.0
NAN非数字(Not a Number)0.0/0.0
HUGE_VAL表示无穷大的double值HUGE_VAL
FLT_MAXfloat最大值std::numeric_limits<float>::max()
FLT_MINfloat最小正值std::numeric_limits<float>::min()

3.3 浮点环境

  • <cfenv>头文件提供浮点环境控制
  • 常见浮点异常:
  • FE_DIVBYZERO
  • FE_INEXACT
  • FE_INVALID
  • FE_OVERFLOW
  • FE_UNDERFLOW

四、浮点运算与类型转换

4.1 算术运算

  • 支持基本算术运算:+, -, *, /
  • 数学函数在<cmath>中定义:
    cpp #include <cmath> double result = std::sqrt(2.0);

4.2 类型转换

4.2.1 隐式转换

  • 遵循从小到大的转换规则:floatdoublelong double
  • 整数可以隐式转换为浮点数

4.2.2 显式转换

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 double d = 3.14;
2 float f = static_cast<float>(d); // C++风格转换
3 float f2 = (float)d; // C风格转换

4.3 浮点与整型的比较

  • 比较时整型会转换为浮点型
  • 注意精度丢失问题

五、浮点类型的实际应用

5.1 何时使用哪种类型

  • float:内存受限场景,不需要高精度
  • double:默认选择,适合大多数应用
  • long double:需要极高精度的科学计算

5.2 性能考虑

  • 现代CPU通常对double有优化,性能与float相差不大
  • SIMD指令可以并行处理多个float运算

5.3 避免常见陷阱

避免相等比较

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 // 错误方式
2 if (a == b) { ... }
3
4 // 正确方式
5 const double epsilon = 1e-10;
6 if (std::abs(a - b) < epsilon) { ... }

避免大数吃小数

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 double big = 1e20;
2 double small = 1.0;
3 // big + small == big,因为small被忽略了

注意累积误差
- 多次运算可能导致误差累积
- 对于金融计算,考虑使用定点数库

六、C++标准库支持

6.1 <limits>头文件

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <limits>
2 std::numeric_limits<double>::max(); // 最大值
3 std::numeric_limits<float>::min(); // 最小正值
4 std::numeric_limits<long double>::digits10; // 十进制精度位数

6.2 <cmath>数学函数

函数描述
std::sqrt(x)平方根
std::pow(x,y)x的y次方
std::exp(x)e的x次方
std::log(x)自然对数
std::log10(x)以10为底的对数
std::sin(x)正弦
std::cos(x)余弦
std::tan(x)正切
std::ceil(x)向上取整
std::floor(x)向下取整
std::round(x)四舍五入
std::fmod(x,y)浮点余数
std::isnan(x)检查是否为NaN
std::isinf(x)检查是否为无穷大

6.3 <iomanip>格式化输出

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <iostream>
2 #include <iomanip>
3
4 double d = 1.23456789;
5 std::cout << std::setprecision(5) << d; // 输出1.2346

七、C++11/14/17/20新增特性

7.1 十六进制浮点字面量(C++17)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 double d = 0x1.2p3; // 1.2(十六进制) × 2^3 = 9.0

7.2 数学特殊函数(C++17)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <cmath>
2 std::assoc_laguerre(2, 1, 0.5); // 关联拉盖尔多项式

7.3 浮点原子操作(C++20)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <atomic>
2 std::atomic<double> atomic_double(3.14);

8 最佳实践总结

  1. 默认使用double,除非有明确理由使用floatlong double
  2. 避免直接比较浮点数相等,使用容差比较
  3. 注意运算顺序对精度的影响
  4. 了解平台特定的浮点实现差异
  5. 对于关键计算,考虑使用高精度数学库如GMP、MPFR
  6. 使用static_cast进行显式浮点转换
  7. 注意浮点数的序列化和反序列化可能引入精度问题
  8. 避免直接比较浮点数是否相等
  9. 注意浮点运算的累积误差
  10. 科学计算考虑使用long double
  11. 处理货币等精确计算考虑使用定点数或专用库
  12. 注意浮点运算的优化可能改变结果(如-ffast-math
  13. 使用std::numeric_limits获取类型特性

9. 示例代码

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <iostream>
2 #include <cmath>
3 #include <limits>
4 #include <cfenv>
5
6 int main() {
7 // 基本浮点类型
8 float f = 3.14159f;
9 double d = 2.718281828459045;
10 long double ld = 1.6180339887498948482L;
11
12 // 浮点运算
13 double sum = 0.1 + 0.2;
14 std::cout << "0.1 + 0.2 = " << sum << " (可能不等于0.3)\n";
15
16 // 浮点比较
17 if (std::fabs(sum - 0.3) < 1e-10) {
18 std::cout << "0.1 + 0.2 ≈ 0.3\n";
19 }
20
21 // 特殊值
22 double inf = 1.0 / 0.0;
23 double nan = 0.0 / 0.0;
24 std::cout << "inf: " << inf << ", isnan: " << std::isnan(nan) << '\n';
25
26 // 数学函数
27 std::cout << "sqrt(2) = " << std::sqrt(2.0) << '\n';
28 std::cout << "sin(π/2) = " << std::sin(3.14159265358979323846/2) << '\n';
29
30 return 0;
31 }
文章目录