当我在阅读C语言中浮点数的十六进制表示时,我遇到了Stephen Prata的书中的一个特殊数字"0xa.1fp10"。当我将此数字分配给float或double变量,并使用“%a”格式说明符在printf中打印时,结果是0x1.43e000p+13,与原始值不匹配。但两者都是相同的值10364(十进制)。
发生了什么?为什么输出值改变了?如何获得原始数字作为输出?
发生了什么?为什么输出值改变了?如何获得原始数字作为输出?
不幸的是,使用printf
无法在移植性上获得与0xa.1fp10
相同的格式。C标准规定,对于一个非零的正常双精度浮点数,在小数点.
之前应该有一个非零数字,并且需要尽可能多的数字来准确表示值在小数点.
之后的部分。实现可以选择前面多少位放入第一个数字!
然而,C11标准有一个脚注278,它说:
这是问题所在。由于IEEE 754二进制实现可以选择十六进制小数点字符左边的数字,以便后续数字与封装(4位)边界对齐。
double
具有53位尾数; 对于正常数字,第一位为1; 其余的52位都可以被4整除,因此遵循该脚注的实现(我的机器上的Glibc似乎是其中之一),将始终输出任何以0x1.
开头的有限非零浮点数!试试这个最小程序:#include <stdio.h>
int main(void) {
for (double i = 1; i < 1024 * 1024; i *= 2) {
printf("%a %a %a\n", 1.0 * i, 0.7 * i, 0.67 * i);
}
}
在我的电脑上的输出为
0x1p+0 0x1.6666666666666p-1 0x1.570a3d70a3d71p-1
0x1p+1 0x1.6666666666666p+0 0x1.570a3d70a3d71p+0
0x1p+2 0x1.6666666666666p+1 0x1.570a3d70a3d71p+1
0x1p+3 0x1.6666666666666p+2 0x1.570a3d70a3d71p+2
0x1p+4 0x1.6666666666666p+3 0x1.570a3d70a3d71p+3
0x1p+5 0x1.6666666666666p+4 0x1.570a3d70a3d71p+4
0x1p+6 0x1.6666666666666p+5 0x1.570a3d70a3d71p+5
0x1p+7 0x1.6666666666666p+6 0x1.570a3d70a3d71p+6
0x1p+8 0x1.6666666666666p+7 0x1.570a3d70a3d71p+7
0x1p+9 0x1.6666666666666p+8 0x1.570a3d70a3d71p+8
0x1p+10 0x1.6666666666666p+9 0x1.570a3d70a3d71p+9
0x1p+11 0x1.6666666666666p+10 0x1.570a3d70a3d71p+10
0x1p+12 0x1.6666666666666p+11 0x1.570a3d70a3d71p+11
0x1p+13 0x1.6666666666666p+12 0x1.570a3d70a3d71p+12
0x1p+14 0x1.6666666666666p+13 0x1.570a3d70a3d71p+13
0x1p+15 0x1.6666666666666p+14 0x1.570a3d70a3d71p+14
0x1p+16 0x1.6666666666666p+15 0x1.570a3d70a3d71p+15
0x1p+17 0x1.6666666666666p+16 0x1.570a3d70a3d71p+16
0x1p+18 0x1.6666666666666p+17 0x1.570a3d70a3d71p+17
0x1p+19 0x1.6666666666666p+18 0x1.570a3d70a3d71p+18
0x1.
,然后是所有实际尾数的十六进制值,去掉尾随的0
字符并添加p+
指数。
。
之前使用一个完整的半字节,其值从0x8
到0xF
(第一位始终为1),并且点后最多有15个半字节。#include <stdio.h>
int main(void) {
for (long double i = 1; i < 32; i ++) {
printf("%La\n", i);
}
}
查看它是否符合这个期望...
0x0.
来表示这些双精度值,后面跟着尾数的实际十六进制数字,尾随零已经被删除,并且固定指数为-1022
- 再次强调,这种表示方法是最容易实现和计算速度最快的。i < 1024*;
- user6947330x
和p
之间的数字(和句点)是十六进制数码,称为有效数字。在p
之后的数字是十进制数码,表示要将有效数字乘以2的幂。
在0xa.1fp10
中,有效数字是a.1f
。这代表着数字10•160 + 1•16−1 + 15•16−2,等于10 + 31/256,即2591/256。
然后p10
表示将其乘以21024,因此结果为2591/256 • 1024 = 10,364。
1 当使用%a
时,C标准将其缩放方式留给实现来选择,但小数点前恰好有一个数字,如果数字处于浮点格式的正常范围内,则该数字非零,并且小数点后的位数等于精度。
从C语言标准所要求的表示方式来看,实际上并不存在一种特定的表示方式。该语言只要求在小数点前面恰好有一个十六进制数字,并且如果数字被标准化且本身不为零,则该数字必须非零。这样对于大多数标准化的浮点数,就有四种可能的表示方式。