了解浮点数(第0部分)

您好,Khabrovites。 我很喜欢浮点寄存器的话题了很长时间。 我一直担心如何输出到屏幕等。 我记得,很久以前在大学里,我正在实现我的由512位组成的浮点数类。 我唯一无法意识到的就是输出到屏幕上。

我一有空,就把旧的拿走了。 我给自己拿了一个笔记本,离开了。 我想自己考虑所有事情,只是偶尔看看IEEE 754标准。
这就是全部。 对于那些感兴趣的人,我要猫。

要掌握这篇文章,您需要了解以下内容:一点点,一个二进制系统,负知识程度的算术。 本文不会影响处理器级别的实现的工程细节以及规范化和非规范化的数字。 更加着重于将数字转换为二进制数,反之亦然,并解释了通常如何以位的形式存储浮点数。

浮点数是一种非常强大的工具,您需要能够正确使用。 它们不像整数寄存器那样普遍,但是如果它们能被熟练地缓慢渗透,也不会那么复杂。

在今天的文章中,我将以32位寄存器为例。 双精度数字(64位)的工作原理完全相同。

首先,让我们讨论一下浮点数是如何存储的。 最旧的31位有意义。 单一表示数字是负数,而零则相反。 接下来是8位指数。 这8位是通常的无符号数字。 最后是尾数的23位。 为方便起见,我们将符号表示为S,将指数表示为E,并将尾数表示为M。

我们得到了一般公式 1s\乘M\乘2E127

尾数被认为是一个隐式的单个位。 也就是说,尾数将为24位,但是由于最高的23位始终为1,因此您无法将其写下来。 因此,这种“限制”将使我们能够代表任何数字。

尾数是一个普通的二进制数,但与整数不同,最高有效位是2 ^ 0度,然后是递减度。 这是参展商派上用场的地方。 取决于其值,高两位的功率增加或减少。 这就是这个想法的全部天才。

让我们尝试通过一个很好的例子来说明这一点:

想象一下数字3.625的二进制形式。 首先,我们将此数字除以2的幂。 3.625=2+1+0.5+0.125=1\乘21+1\乘20+1\乘21+0\乘22+1\乘23

高二的程度等于一。 E-127 =1。E= 128。

0 1,000,000 1,101,000,000,000,000,000,000

那就是我们所有的电话。

让我们也尝试相反的方向。 假设我们有32位,任意32位。

0 10000100(1)11011100101000000000000

括号中指示了相同的隐式高位。

首先,计算指数。 E =132。因此,高二的程度将等于5。总的来说,我们有以下数字:
25+24+23+21+20+21+24+26=
=32+16+8+2+1+0.5+0.0625+0.015625=59.578125

很容易猜到我们只能存储24度的两个范围。 因此,如果两个数字的指数差异大于24,则相加后,该数字将保持等于其中较大的数字。

为了方便转换,我在C中上传了一个小程序。

#include <stdio.h> union IntFloat { unsigned int integerValue; float floatValue; }; void printBits(unsigned int x) { int i; for (i = 31; i >= 0; i--) { if ((x & ((unsigned int)1 << i)) != 0) { printf("1"); } else { printf("0"); } if (i == 31) { printf(" "); } if (i == 23) { printf(" "); } } printf("\n"); } int main() { union IntFloat b0; b0.floatValue = 59.578125; printBits(b0.integerValue); b0.integerValue = 0b01000010011011100101000000000000; printf("%f\n", b0.floatValue); return 0; } 

网格步长是两个相邻浮点数之间的最小差。 如果我们将这样一个数字的比特序列表示为正整数,则相邻的浮点数的比特单位将有所不同。

可以用其他方式表示。 两个相邻的浮点数将相差2 ^(E-127-23)。 即,相差等于最低有效位的值。

作为证明,您可以更改代码中的main并重新编译。

 union IntFloat b0, b1, b2; b0.floatValue = 59.578125F; b1.integerValue = b0.integerValue + 1; b2.floatValue = b1.floatValue - b0.floatValue; printBits(b0.integerValue); printBits(b1.integerValue); printBits(b2.integerValue); printf("%f\n", b0.floatValue); printf("%f\n", b1.floatValue); printf("%f\n", b2.floatValue); short exp1 = 0b10000100; short exp2 =0b01101101; /*  ,       */ b0.integerValue = 0b01000010011111111111111111111111; b1.integerValue = b0.integerValue + 1; b2.floatValue = b1.floatValue - b0.floatValue; printBits(b0.integerValue); printBits(b1.integerValue); printBits(b2.integerValue); printf("%f\n", b0.floatValue); printf("%f\n", b1.floatValue); printf("%f\n", b2.floatValue); /*   */ printf("%d %d\n", exp1, exp2); 

我认为今天您可以四舍五入,否则结果太长。 下次,我将写有关添加浮点数和舍入时失去精度的文章。

PS:我了解到我没有涉及非正规数字等问题。 我只是不想加载太多文章,并且几乎在一开始就可以在IEEE 754标准中轻松找到此信息。

Source: https://habr.com/ru/post/zh-CN456714/


All Articles