在 C++ 中有以下 3 种数据类型可以表示浮点数,分别是 float、double 和 long double。
float 数据类型被认为是单精度。double 数据类型通常是 float 的两倍大小,因此被认为是双精度。顾名思义,long double 数据类型又比 double 要大。这些数据类型的确切大小取决于当前使用的计算机。唯一可以保证的是:
- double 至少与 float 一样大。
- long double 至少与 double一样大。
数据类型 | 关键字 | 大小 | 范 围 | 有效数字 |
---|---|---|---|---|
单精度 | float | 4字节 | 数字介于 ±3.4E-38 和 ±3.4E38 之间 | 7或8 |
双精度 | double | 8字节 | 数字介于 ±1.7E-308 和 ±1.7E308 之间 | 15或16 |
高双精度 | long double | 8字节 | 数字介于 ±1.7E-308 和 ±1.7E308 之间 | 16或16 |
1. 有效数字的位数
也就是说,对于double,第16位有效数字是不可信的,那么第15位就是可信的吗?看下面的例子
double a = 1e-20;
std::cout << "a is " << std::setprecision(30) << a << std::endl;
输出
9.9999999999999994515327145421e-21
也就是说存储的值与真实真的差小于1e-15
2. 类型强转
double a = 1506223285.61999999;
uint64_t b = static_cast<uint64_t>(a * 100);
std::cout << "a is " << std::setprecision(30) << a << std::endl;
std::cout << "b is " << b << std::endl;
输出
a is 1506223285.61999988555908203125
b is 150622328562
虽然类型强转是进行截断,但a有可能存储的就是1506223285.62,所以很在意精度的时候最好不要用这种类型强转,而是使用四舍五入再强转
以上是个人的一些理解,如有错误,感谢指正。
3. nan
nan的意思是not a number,在很多语言中都有
如果在编译时增加了-ffast-math -ffast-math -use_fast_math选项(用于浮点数计算加速),则可能会导致std::nan失效,不再能有效判断nan
此果需要我们自己写一个nan函数
bool isNan(float f) {
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}