在大多数编程语言中,浮点数的表示方式与科学记数法很相似:带有指数和尾数(也称为有效数字)。比如9.2,一个非常简单的数字实际上是这个分数:5179139571476070 * 2 -49

指数是-49和尾数的位置5179139571476070。不能用这种方式表示一些十进制数的原因是指数和尾数都必须是整数。换句话说,所有浮点数必须是整数乘以2的整数幂。

9.2可以简单地说92/10,但是如果n限于整数值,则10不能表示为2 n。

看到数据

首先,有一些函数可以查看构成32位和64位的组件float。如果您只关心输出(Python中的示例):def float_to_bin_parts(number, bits=64):

if bits == 32:          # single precision
int_pack      = 'I'
float_pack    = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64:        # double precision. all python floats are this
int_pack      = 'Q'
float_pack    = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]

这个函数背后有很多复杂性,它解释起来很简单,但是如果你感兴趣的话,我们目的的重要资源就是struct模块。

Python float是一个64位的双精度数字。在其他语言中,例如C,C ++,Java和C#,双精度具有单独的类型double,通常实现为64位。

当我们用我们的例子调用该函数时9.2,这是我们得到的:>>> float_to_bin_parts(9.2)['0', '10000000010', '0010011001100110011001100110011001100110011001100110']

解释数据

你会看到我把返回值分成三个部分。这些组件是:标志

指数

尾数(也称为有效,或分数)

标志

符号作为单个位存储在第一个组件中。这很容易解释:0意味着浮动是一个正数; 1意味着它是消极的。因为9.2是正面的,我们的标志值是0。

指数

指数作为11位存储在中间组件中。在我们的例子中0b10000000010。在十进制中,表示值1026。这个组件的一个怪癖是你必须减去一个等于2 (位数) - 1 - 1的数字来得到真正的指数; 在我们的例子中,这意味着减去 0b1111111111(十进制数1023)以获得真正的指数,0b00000000011(十进制数3)。

尾数

尾数作为52位存储在第三个组件中。但是,这个组件也有一个怪癖。要理解这个怪癖,请考虑科学记数法中的数字,如下所示:6.0221413x10 23

尾数将是6.0221413。回想一下,科学记数法中的尾数总是以一个非零数字开头。二进制也是如此,除了二进制只有两位数:0和1。所以二进制尾数始终以1!开头!存储浮点数时,1省略二进制尾数的前面以节省空间; 我们必须将它放回第三个元素的前面以获得真正的尾数:1.0010011001100110011001100110011001100110011001100110

这不仅仅是一个简单的加法,因为存储在我们的第三个分量中的比特实际上代表了尾数的小数部分,在小数点的右边。

当处理十进制数时,我们通过乘以或除以10的幂来“移动小数点”。在二进制中,我们可以通过乘以或除以2的幂来做同样的事情。由于我们的第三个元素有52位,我们除以通过2 52将它向右移动52个位置:0.0010011001100110011001100110011001100110011001100110

在十进制,这是同分675539944105574的4503599627370496获得0.1499999999999999。(这是比率的一个示例,可以精确地以二进制表示,但仅大约以十进制表示;有关更多详细信息,请参阅:675539944105574/4503599627370496。)

现在我们已经将第三个组件转换为小数,添加1给出了真正的尾数。

重新安装组件符号(第一个组成部分):0表示正数,1表示负数

指数(中间分量):减去2 (位数) - 1 - 1得到真指数

尾数(最后一个分量):除以2 (位数)并加上1以得到真正的尾数

计算数量

将所有三个部分放在一起,我们给出了这个二进制数:1.0010011001100110011001100110011001100110011001100110 x 10 11

然后我们可以从二进制转换为十进制:1.1499999999999999 x 2 3(不准确!)

并且9.2在存储为浮点值之后,乘以显示我们以()开头的数字的最终表示:9.1999999999999993

代表一个分数

9.2

现在我们已经建立了数字,可以将它重建为一个简单的部分:1.0010011001100110011001100110011001100110011001100110 x 10 11

将尾数转换为整数:10010011001100110011001100110011001100110011001100110 x 10 11-110100

转换为十进制:5179139571476070 x 2 3-52

减去指数:5179139571476070 x 2 -49

将负指数转换为除法:5179139571476070/2 49

乘以指数:5179139571476070/562949953421312

等于:9.1999999999999993

9.5>>> float_to_bin_parts(9.5)['0', '10000000010', '0011000000000000000000000000000000000000000000000000']

您已经可以看到尾数只有4位数后跟一大堆零。但是让我们来看看节奏。

组装二进制科学记数法:1.0011 x 10 11

移动小数点:10011 x 10 11-100

减去指数:10011 x 10 -1

二进制到十进制:19 x 2 -1

分数的负指数:19/2 1

乘以指数:19/2

等于:9.5

进一步阅读