像这样的简单代码printf("hex representation for %f is [%a]n", 3.14, 3.14);
,根据下面的参考网站,我希望结果是0x4048f5c3
(完全二进制版本为:0100 0000 0100 1000 1111 0101 1100 0011
,0x4.8f5c3p-1
(,但编译的可执行文件显示[0xc.8f5c3p-2]
(二进制:1100.1000 1111 0101 1100 0011
(,为什么C编译器显示指数为-2而不是-1?
编译器设置为:
"command": "c:/msys64/mingw64/bin/gcc.exe",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}\${fileBasenameNoExtension}.exe",
"-Wall",
"-Werror",
"-std=c11"
参考:https://users.cs.fiu.edu/~downyt/cop2400/float.htmhttps://gregstoll.com/~gregstoll/foattohex/
您正在使用的网站显示浮点数的二进制表示。例如,3.14
是big-endian中的40 48 F5 C3
,或者是little-endian中的C3 F5 48 40
。
C中的十六进制表示是以16为底的实际浮点数,而不是二进制表示。CCD_ 10表示CCD_。如果我们使用通常的转换算法将其转换为十进制,我们得到3.14
:
12(C) * 16^0 + 8 * 16^(-1) + 15(F) * 16^(-2) + 5 * 16^(-3) + 12(C) * 16^(-4) + 3 * 16^(-5) = 12 + 0.5 + 0.05859 + ... = 12.56
(带近似值(
现在乘以2^(-2)
,或者除以4
,我们得到3.14
。
这里显示了这两种表示之间的差异(注意,从技术上讲,这个程序会导致C中的未定义行为,因为uint32_t*
到float*
的强制转换后面跟着去引用,但在这种情况下,行为是使用二进制表示来创建浮点数,正如人们所期望的那样(:
#include <stdio.h>
#include <inttypes.h>
// Assuming IEEE 754 representation of 32-bit floats
int main(void)
{
float x = 0xC.8F5C3p-2;
uint32_t y = 0x4048F5C3;
printf("Base-16 representation of %f is: %An", x, x);
printf("Binary representation of %f is: 0X%"PRIX32"n", *(float*)&y, y);
}
这是我在电脑上得到的输出:
Base-16 representation of 3.140000 is: 0XC.8F5C3P-2
Binary representation of 3.140000 is: 0X4048F5C3
为什么C编译器将指数显示为-2而不是-1?
这里的问题是浮点表示——无论是使用二进制、十进制还是十六进制——往往都不是唯一的。看看你以10为基数的数字,它的科学记数法可能是
3.14×100
或
0.314×101
甚至
31.4×10-1
或
0.0314×102
为了解决唯一性问题,我们通常定义一个";归一化形式"——但是可以有多种方法来定义它!例如,我们可以说小数点的左边应该只有一个数字(3.14×100(,或者我们可以说,小数点的右边应该有0,但右边紧接着有一个非零数字(0.314×101(。规范化规则还有其他选择。
当谈到printf %a
时,它变得更加令人困惑,因为有效位数字是十六进制的,但指数是两个的幂。因此,即使我们说我们想要";一个数字";在基数点的左边,我们有四种不同的数字选择,因为我们可以有效地将基数点放在十六进制数字的任何位之间!
我们可以用3.14的例子来说明这一点。在二进制中,四舍五入到24个有效位(即IEEE单精度,也称为float
(,它是
0b1.10010001111010111000011×21
如果我们直接将其转换为十六进制,我们就会得到
0x1.91eb86×21
但我们可以将有效位向左移动1、2或3位,并且在基点的左侧仍然只有一个十六进制数字:
0x3.23d70c×20
0x6.47ae18×2-1
0xc.8f5c30×2-2
事实上,在我的电脑上,%a
将3.14f
打印为0x1.91eb86p+1
。但你说你的印刷0xc.8f5c3p-2
(@DarkAtom也是如此(。但正如我们刚刚看到的,这两种表示是等价的。
正如其他答案和注释所解释的,您认为可能看到的十六进制数字0x4048f5c3
与值没有直接关系;它是IEEE-754单精度原始编码的十六进制表示。隐藏在该编码中的是0的符号位、0x80
的有偏指数和0x91eb86
或0x48f5c3
的有效位,具体取决于您如何看待它。但现在我们可以很容易地看到它们是如何组合在一起的,因为有效位与我们看到的十六进制模式相匹配,并且有偏指数值0x80
的实际指数为128-127=1。(我说过编码的有效位"取决于你如何看待它,0x91eb86
或0x48f5c3
",但你可以相信我的话,它都对应于0x1.91eb86 × 2¹
,其中前导1是隐含的。(
不过,我无法解释你提到的0x4.8f5c3p-1
是从哪里来的。