c语言 - 用 printf( "%a" , 3.14) 表示十六进制浮点数



像这样的简单代码printf("hex representation for %f is [%a]n", 3.14, 3.14);,根据下面的参考网站,我希望结果是0x4048f5c3(完全二进制版本为:0100 0000 0100 1000 1111 0101 1100 00110x4.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

事实上,在我的电脑上,%a3.14f打印为0x1.91eb86p+1。但你说你的印刷0xc.8f5c3p-2(@DarkAtom也是如此(。但正如我们刚刚看到的,这两种表示是等价的。

正如其他答案和注释所解释的,您认为可能看到的十六进制数字0x4048f5c3与值没有直接关系;它是IEEE-754单精度原始编码的十六进制表示。隐藏在该编码中的是0的符号位、0x80的有偏指数和0x91eb860x48f5c3的有效位,具体取决于您如何看待它。但现在我们可以很容易地看到它们是如何组合在一起的,因为有效位与我们看到的十六进制模式相匹配,并且有偏指数值0x80的实际指数为128-127=1。(我说过编码的有效位"取决于你如何看待它,0x91eb860x48f5c3",但你可以相信我的话,它都对应于0x1.91eb86 × 2¹,其中前导1是隐含的。(

不过,我无法解释你提到的0x4.8f5c3p-1是从哪里来的。

最新更新