C++17 十六进制浮点字面量
回顾普通浮点字面量
平时常见的浮点字面量使用十进制表示:
double a = 3.14;
double b = 1.5e2; // 1.5 × 10^2 = 150
double c = 2.5e-3; // 2.5 × 10^-3 = 0.0025
其中:
e或E表示十进制指数;- 指数部分的底数是 10。
十六进制浮点字面量
C++17 支持直接书写十六进制浮点字面量。
基本形式为:
0x十六进制有效数字p二进制指数
例如:
double x = 0x1.8p1;
它表示:
\[
0x1.8 \times 2^1
\]
这里需要注意:
- 前缀使用
0x或0X; - 有效数字使用十六进制;
- 指数标记必须使用
p或P; - 指数的底数是 2,而不是 10。
为什么指数用 p
十六进制数字中,字母 e 本身就是合法数字:
0x1e
这里的 e 表示十六进制数字 14。
因此,十六进制浮点数不能再使用 e 表示指数,只能使用 p 或 P。
计算示例
0x1p0
double x = 0x1p0;
表示:
\[
1 \times 2^0 = 1
\]
所以 x 的值为 1。
0x1p3
double x = 0x1p3;
表示:
\[
1 \times 2^3 = 8
\]
0x1.8p1
十六进制小数:
\[
0x1.8 = 1 + \frac{8}{16} = 1.5
\]
因此:
\[
0x1.8p1 = 1.5 \times 2^1 = 3
\]
double x = 0x1.8p1; // 3.0
0x1.4p2
先计算有效数字:
\[
0x1.4 = 1 + \frac{4}{16} = 1.25
\]
再乘以二进制指数:
\[
1.25 \times 2^2 = 5
\]
double x = 0x1.4p2; // 5.0
负指数
double x = 0x1p-2;
表示:
\[
1 \times 2^{-2} = \frac{1}{4} = 0.25
\]
类型后缀
十六进制浮点字面量也可以使用浮点类型后缀。
auto a = 0x1.8p1; // double
auto b = 0x1.8p1f; // float
auto c = 0x1.8p1L; // long double
规则与普通浮点字面量一致:
| 后缀 | 类型 |
| 无后缀 | double |
f 或 F | float |
l 或 L | long double |
与普通浮点写法对比
| 写法 | 含义 | 结果 |
1.5e2 | \(1.5 \times 10^2\) | 150 |
0x1.8p1 | \(1.5 \times 2^1\) | 3 |
0x1p4 | \(1 \times 2^4\) | 16 |
0x1p-3 | \(1 \times 2^{-3}\) | 0.125 |
为什么有这种写法
计算机中的浮点数通常采用二进制表示。
十进制小数有时不能被二进制精确表示,例如:
double x = 0.1;
而十六进制浮点字面量与二进制浮点表示关系更直接。
例如:
double x = 0x1p-3;
它准确表示:
\[
2^{-3} = 0.125
\]
因此十六进制浮点字面量常用于:
- 精确表示二进制浮点值;
- 浮点算法测试;
- 底层数值程序;
- 需要明确控制浮点常量的场景。
常见错误
使用 e 表示指数
错误:
double x = 0x1.8e2;
在十六进制中,e 会被当作数字的一部分。
正确写法:
double x = 0x1.8p2;
省略指数部分
十六进制浮点字面量必须包含 p 指数部分。
错误:
double x = 0x1.8;
正确:
double x = 0x1.8p0;
把指数理解为十进制指数
double x = 0x1p3;
它表示:
\[
1 \times 2^3
\]
不是:
\[
1 \times 10^3
\]