Floating Point Representation and Machine Representation of Decimal Digits (IEEE 754 Standards)

Jul. 23, 2022

二进制与十进制之间的转换

将十进制数转换为二进制数

将一个十进制数字转化为二进制,最简单的方式是将数字的整数部分和小数部分分别对待,比如对于十进制数字 $(53.7)_{10}$ 可以写作 $(53.7) _{10}=(53) _{10}+(0.7) _{10}$,将整数部分和小数部分分别转化为二进制数字,再把结果组合起来,就可以得到 $53.7$ 完整的二进制表示。

(1)整数部分

在将十进制转化为二进制时,将整数连续被 2 除并保留余数,余数只可能是 0 或者 1

\[\begin{align*} 53\ 除\ 2&=26\ 余\ 1\\ 26\ 除\ 2&=13\ 余\ 0\\ 13\ 除\ 2&=6\ 余\ 1\\ 6\ 除\ 2&=3\ 余\ 0\\ 3\ 除\ 2&=1\ 余\ 1\\ 1\ 除\ 2&=0\ 余\ 1\\ \end{align*}\]

最后,将余数从下到上排列,就可以得到 $(53)_{10}=(110101.)_2$

(2)小数部分

将上述的计算过程反过来就可以将十进制小数 $(0.7)_{10}$ 转化为二进制。将小数部分不断乘 2 并记录整数部分

\[\begin{align*} 0.7\times2&=0.4+1\\ 0.4\times2&=0.8+0\\ 0.8\times2&=0.6+1\\ 0.6\times2&=0.2+1\\ 0.2\times2&=0.4+0\\ 0.4\times2&=0.8+0\\ \cdots \end{align*}\]

可以看到,第6步和第2步的表达式是一致的,因此整个过程会呈现出一种循环,因此可以记作 $(0.7) _{10}=(0.1\overline{0110}) _2$.

将整数部分和小数部分放到一起,可以得到

\[(53.7)_2=(110101.1\overline{0110})_2\notag\]

将二进制数转换为十进制数

将二进制数转换为十进制,还是需要将整数部分和小数部分分别计算。

(1)整数部分

二进制数 $(10101) _2$ 可以转换为十进制 $(21) _{10}$

\[1\times2^0+0\times2^1+1\times2^2+0\times2^3+1\times2^4=21\notag\]

(2)小数部分

二进制小数部分的转换,分为两种情形:有限位小数的转换、无限位小数的转换。

1️⃣ 如果小数部分有限,则以类似的方式进行转换,如

\[(0.1011)_2=1\times\dfrac12+0\times\dfrac14+1\times\dfrac18+1\times\dfrac{1}{16}=(\dfrac{11}{16})_{10}\notag\]

2️⃣ 如果小数部分有无限位时,转化会变得复杂一点,一种简单的方法是利用2乘的平移性质。

以将 $x=(0.\overline{1011})_2$ 转化为十进制为例。把 $x$ 和 $2^4$ 相乘,意味着在二进制中向左平移4位,则有:

\[\begin{align*} x&=0000.\overline{1011}\\ 2^4x&=1011.\overline{1011} \end{align*}\]

相减得到

\[(2^4-1)x=(1011)_2=(11)_2\notag\]

于是可以解出

\[x=\dfrac{11}{15}\notag\]

如果分数部分没有立即循环,例如对于 $x=0.10\overline{101}$,则有

\[\begin{align*} x&=0.10\overline{101}\\ y=2^2x&=10.\overline{101}\\ \end{align*}\]

令 $z=0.\overline{101}$,则有

\[\begin{align*} 2^3z&=101.\overline{101}\\ z&=000.\overline{101} \end{align*}\]

则可以解出

\[\begin{align*} &(2^3-1)z=(101)_2=5\\ \Rightarrow&z=\dfrac57 \end{align*}\]

\[\begin{align*} &2^2x=(10.\overline{101})_2=2+\dfrac57\\ \Rightarrow&x=\dfrac{19}{28} \end{align*}\]


IEEE 754 标准定义的浮点数

IEEE 754 标准化

IEEE浮点标准所定义的浮点数字主要包含三个部分,分别是:符号($+$ 或者 $-$)、尾数和指数。浮点数有三种常用的精度级别:单精度、双精度和扩展精度(也称为长双精度)。这三种精度都可以用标准化的IEEE浮点数表示为:

image-20220721235015059

其中,标准化意味着,主导数位(最左边的一位)必须是1。

注:数字 $0$ 就明显不能被标准化,它也被称为异常浮点数字,后面会再提这一点。

三种浮点数精度的数位(bit,即 $s+b+p$ 的位数加和)分别是32、64、80,这些数位的分配方式如下表所示:

精度 符号(s) 指数(p) 尾数(b) $s+b+p$
单精度 1 8 23 32
双精度 1 11 52 64
长双精度(扩展精度) 1 15 64 80

机器精度

根据 IEEE 754 所定义的标准化浮点格式,数字 $1$ 的双精度浮点格式可以表示为

\[+1.0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\times2^0\notag\]

注:最左边的1不算入52位尾数当中。

下一个比数字1大的浮点数为:

\[+1.0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0001\times2^0\notag\]

由此,我们就可以得到机器精度的定义。

机器精度(machine epsilon),记作 $\varepsilon_{mach}$,定义为 1 和比 1 大的最小的浮点数之间的距离。对于上述IEEE双精度浮点数,有 $\varepsilon_{mach}=2^{-52}\approx2.2^{-16}$ 。但是,由上述定义可以看出,并不是任意两个相邻浮点数之间的距离都是 $\varepsilon_{mach}$ 。任意两个相邻浮点数之间的距离受它们整数部分的影响,因为整数部分和小数部分一起来分担尾数的52位二进制数;更准确地讲,任意两个相邻浮点数之间的距离受后面指数部分的影响,其值是 $2^{-52}\times2^{p}$

我们很容易验证这一点。在MATLAB中,得到 $2^{52}$(它的双精度浮点数表示的指数部分为$(52)_{10}$,尾数部分均为$0$) 的具体值以及它的浮点数表示:

1
2
3
4
5
6
7
>> format long
>> 2^52
ans =
     4.503599627370496e+15
>> num2hex(ans)
ans =
    '4330000000000000'

之后,计算比它大的下一个浮点数所表示的数字:

1
2
3
hex2num('4330000000000001')
ans =
     4.503599627370497e+15

可以看到,它们之间的间隔为 $2^{-52}\times2^{52}=1$。

也就是说,双精度计算机并不能精确表示 $4503599627370496$ 和 $4503599627370497$ 之间的任意一个小数,哪怕是 $4503599627370496.1$ 也不可以!

2023.04.23 注:

这样就是说,在$4503599627370496$后面的一段范围之内,我们只能使用双精度浮点数来表示整数(其间隔为1)。那么我们从哪个数字开始,我们不能在开始表示连续的整数了呢?根据前面所提到的两个相邻浮点数之间的间隔公式$2^{-52}\times2^{p}$可以得到:当$p=53$(即$2^{53}$)开始,就不能表示连续整数了——相邻两个浮点数之间的距离为$2^{-52}\times2^{p}=2$。

1
2
3
4
5
6
7
>> format long
>> 2^53
ans =
  9.007199254740992e+15
>> num2hex(2^53)
ans =
 '4340000000000000'
1
2
3
4
 % The next floating piont number
 >> hex2num('4340000000000001')
ans =
     9.007199254740994e+15

注:刚开始可能会有这样的疑问:34等于十进制的52,为什么在这里就表示十进制的53呢?实际上,十六进制数434是一个整体,不仅包含了指数位(11位二进制),还包含了前面的符号位(1位二进制),我们不能分割来看。根据后面将要提到的点数的机器表示规则——指数偏差$\eqref{bias}$就可以得到,指数位(即53)的二进制表示为$10000110100$(11位),再在最前方加入表示符号位的$0$,最终得到的前12位的$010000110100$,其十六进制表示就是434

而这一值($2^{53}$)似乎是很重要的。MATLAB专门定义了flintmax函数用于获取“Largest consecutive integer in floating-point format”

1
2
3
>> flintmax('double')
ans =
  9.007199254740992e+15

我们可以看看 $4503599627370496.1$ 在计算机中是如何表示的:

1
2
3
>> num2hex(4503599627370496.1)
ans =
    '4330000000000000'

可以看出,$4503599627370496.1$ 的机器表示和 $4503599627370496$ 的机器表示是完全一致的。那么,为什么是一致的?这就需要后面要提到的“拟合”的概念。

拟合

有很多很简单的数字无法用浮点数来精确表示,比如上面提到的 $4503599627370496.1$ ,再比如 $(0.1)_{10}$ 的二进制表示为 $(0.0\overline{0011})_2$ ,它就不可能用有限位的浮点数字表示。那么对于这样的数字,我们必须以某种方式对浮点数进行截断从而拟合想要的数字,那么我们采用哪种方式呢?哪种方式更为合理呢?

截断和舍入

第一种方法是截断。截断的方法简单粗暴,即采取直接将末端之外的数位进行舍弃。对于双精度浮点数而言,就是把尾数超过右边第52位的数字直接丢掉。这种策略非常简单,但是这种方法通常会把结果向 $0$ 移动,因此这是一种有偏的方式。

第二种方法是舍入。对于十进制,如果下一位的数字是 5 或者比 5 大,数字通常向上进位,反之则舍去。在二进制中也有同样的策略,如果下一位的数位为 1 ,则向上进位,反之则舍去。具体而言,在IEEE执行的默认的舍入技术中,如果双精度浮点数的第53位数是 1 ,那么就给第 52 位加1(向上进位),如果第 53 位是 0,那么就直接舍去。⚠️但是有一个例外,如果第 52 位后面的数位是 $1000\cdots$ (即只有第53位为1,后面全是0),它正好在向上进位和舍去的中间,那么我们需要依据如何使得第 52 位等于 0 来确定是进位还是舍去。

为什么会有这种例外呢?

舍入法则的本质是使经过舍入处理后的浮点数离原始数字最接近(因此它也被称为最近舍入法则)。舍入造成的误差可能是向上的误差,也有可能是向下的误差,但是两种情形有着相同的可能性。但是对于上述的例外情况,有两个距离原始数字相等的浮点数,在这种情况下,我们无论是选择“舍”还是选择“入”,都会表现出系统地向上或者向下的倾向,都是一种有偏的方式。我们试图避免由于有偏的舍入而在长计算中表现出的缓慢漂移。因此,当出现这种平局的情况,我们选择了使最后一位(第52位)为 0 的方法。虽然这种方法看起来比较随意,但是这样的选择并没有表现出对于向上或者向下的倾向。

IEEE 舍入最近法则

对于双精度浮点数,如果在二进制数右边第 53 位是 0 ,则向下舍去;如果第 53 位是 1,则向上进位。如果第 53 位是 1 ,后面其他所有的已知位都是 0,在这种情况下,当且仅当第 52 位是 1 时进位。

舍入误差

IEEE 754 默认所采用的近似策略是最近舍入法则。对于任意给定的一个十进制数,我们都可以计算它的舍入误差。比如,对于实数 $(9.4) _{10}$,我们可以得到它的二进制表达式 $(9.4) _{10}=(1001.\overline{0110})_2$,将它写作符合 IEEE 754 标准的双精度浮点数:

\[+1.\textcolor{blue}{001\ 0110 \ 0110\ 0110 \ 0110\ 0110 \ 0110\ 0110 \ 0110\ 0110 \ 0110\ 0110 \ 0110\ 0}\ 110\cdots\ \times2^{3}\notag\]

根据舍入原则,舍弃掉的部分为 $0.\overline{1100}\times2^{-52}\times2^3$,进位的部分是 $1\times2^{-52}\times2^3$,最后真正保存在计算机中的浮点数的真实值 $fl(9.4)$ 是

\[\begin{align*} fl(9.4)&=9.4-0.\overline{1100}\times2^{-52}\times2^3+1\times2^{-52}\times2^3\\ &=9.4+(1-0.\overline{1100})\times2^{-52}\times2^3\\ &=9.4+(1-0.8)\times2^{-49}\\ &=9.4+0.2\times2^{-49}\\ \end{align*}\]

其中, $0.2\times2^{-49}$ 称作舍入误差。计算机无法保存 $9.4$,而只能保存 9.4 的浮点数,两者虽然接近并不相等,舍入误差就量化了两者之间的距离。

绝对误差和相对误差

令 $x_c$ 是计算版本 $x$ 的精确度量,则

\[\begin{align*} 绝对误差&=\vert x_c-x\vert\\ 相对误差&=\dfrac{\vert x_c-x\vert}{\vert x\vert}(若 x的度量存在,即x\ne0) \end{align*}\]

对于上面的例子

\[\begin{align*} 绝对误差&=\vert fl(9.4)-9.4\vert=0.2\times2^{-49}\\ 相对误差&=\dfrac{\vert fl(9.4)-9.4\vert}{\vert 9.4\vert}=\dfrac{0.2\times2^{-49}}{9.4}=\dfrac1{47}\times2^{-49} \end{align*}\]

机器精度的意义

在 IEEE 机器算数模型中, $fl(x)$ 的相对舍入误差不会比机器精度的一半大,即:

\[\dfrac{\vert fl(x)-x\vert}{\vert x\vert}\le\dfrac12\varepsilon_{mach}\label{eq1}\]

针对上面的例子

\[\dfrac{\vert fl(9.4)-9.4\vert}{\vert 9.4\vert}=\dfrac1{47}\times2^{-49}=\dfrac8{47}\times2^{-52}\lt \dfrac12\times2^{-52}=\dfrac12\times\varepsilon_{mach}\notag\]

满足式 $\eqref{eq1}$。

证明:

前面提到,在双精度的浮点数的框架下,机器精度为 $\varepsilon_{mach}=2^{-52}$ 。任意假设有两个数字 $x_1$ 和 $x_2$ ,它们刚好可以表示为两个相邻的浮点数,不存在舍入误差,则有

\[\vert fl(x_1)-fl(x_2)\vert=\varepsilon_{mach}\times2^p\notag\]

而任何存在于 $x_1$ 和 $x_2$之间的数字 $a$ 在表示为浮点数时,都遵从舍入法则,舍入误差不超过 $x_1$ 和 $x_2$ 之间的距离的一半(关于两个相邻浮点数之间的距离,上面有提到)

\[\vert fl(a)-a \vert\le \dfrac12\vert fl(x_1)-fl(x_2)\vert=\dfrac12\varepsilon_{mach}\times2^p\label{eq2}\]

而数字 $a$ 的数量级满足

\[2^p\le\vert a\vert\le 2^{p+1}\notag\]

\[\dfrac1{\vert a\vert}\le \dfrac1{2^p}\label{eq3}\]

结合公式 $\eqref{eq2}$ 和 $\eqref{eq3}$ 可以得到:

\[\dfrac{\vert fl(a)-a\vert}{\vert a \vert}\le\dfrac{\dfrac12\varepsilon_{mach}\times2^p}{2^p}=\dfrac12\varepsilon_{mach}\notag\]

当浮点数不是双精度格式而是其他精度格式时(只要是 IEEE 754 标准所规定的精度格式),上述证明过程是类似的,只是机器精度 $\varepsilon_{mach}$ 的具体值不同。

QED

实际上,在上述推导过程中,已经得到了任意一个浮点数 $fl(x)$ 的绝对舍入误差上界,即式 $\eqref{eq2}$

\[\vert fl(x)-x \vert\le \dfrac12\varepsilon_{mach}\times2^p\notag\]

机器表示 (以MATLAB软件为例)

根据上述的分析,符合IEEE 754标准的标准化浮点数都可以写成如下形式:

\[\pm1.bbb\cdots b\times 2^p\notag\]

在机器实现时,以符号s、指数p、尾数b的顺序保存在计算机的字中,以双精度格式为例:

\[s\vert p_1p_2\cdots p_{11}\vert b_1b_2\cdots b_{52}\notag\]

其中:

  1. $s$ 保存了符号位,$0$表示正数,$1$表示负数,即:$\mathrm{sign}=(-1)^s$;

  2. $p_1p_2\cdots p_{11}$ 用于保存指数。11位数位一共可以表示 $0\sim(2^{11}-1)$ 之间,即 $0\sim2047$ 之间,的所有整数。但是计算机在实际保存指数时,并没有采用第1位为符号位(指数位的符号位),其余位为数字的形式,而是使用了指数偏差(Exponent bias)的概念:保存在机器中的11位二进制数表示的指数不是真正的指数,而是保存在计算机中的一个值,真正的指数需要通过以下关系式计算获得:

    \[\text{真正的指数 = 保存在计算机中的指数(由11位二进制数表示)- 指数偏差}\label{bias}\]

    对于双精度而言,它的指数偏差是 $2^{10}-1=1023$。也就是说,11位数位所对应的 $0\sim 2047$ 实际代表着 $-1023\sim 1024$。但是由于一些特殊的需要(后面将要提到),实际上11位所表示的0和2047被保留下来,因此指数的范围实际上只有 $-1022\sim1023$;

  3. $b_1b_2\cdots b_{52}$ 用于保存尾数;

  4. 被保留下来的指数是 $0$ 和 $2047$;

(1)被保留下来的指数 $2047$ ,它的二进制表示为 $(111\ 1111\ 1111)_2$,它用于表示 $\infty$ 和 $\mathrm{NaN}$ 的情况,比如 $\mathrm{Inf}$ 的双精度表示为——前12位分别为 $(1111\ 1111\ 1111)_2$,尾数均为0;$\mathrm{-Inf}$ 的前12位分别为 $(0\vert111\ 1111\ 1111)_2$,尾数均为0;而 $\mathrm{NaN}$ 的前12位分别为 $(1\vert111\ 1111\ 1111)$ ,尾数不全为0。

机器数 例子 十六进制数
$\mathrm{+Inf}$ 1/0 7FF0000000000000
$\mathrm{-Inf}$ -1/0 FFF0000000000000
$\mathrm{NAN}$ 0/0 FFFXXXXXXXXXXXXX(X表示不全为0的位)

我们可以在 MATLAB 中验证一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   % +Inf----------------------------
   >> num2hex(1/0)
   ans =
       '7ff0000000000000'
   >> num2hex(2/0)
   ans =
       '7ff0000000000000'
       
   % -Inf----------------------------
   >> num2hex(-1/0)
   ans =
       'fff0000000000000'
   >> num2hex(-2/0)
   ans =
       'fff0000000000000'
       
   % NaN----------------------------
   >> num2hex(0/0)
   ans =
       'fff8000000000000'

(2)被保留下来的指数 $0$,它的二进制表示为 $(000\ 0000\ 0000)$,它是异常(subnormal)浮点数字(即非标准浮点数字)的标志。由上面的分析可以知道,符合IEEE 754 标准化的浮点数都是“左对齐”的,这意味着最左边的数位假设为1,如果不是1,则通过2乘移位。但是在这种标准化格式的定义下,有一些数字是没有办法表示的,最典型的就是数字 0 无法写成这种标准化的形式。因此,为了拓宽数字的表示范围,IEEE 754标准定义了依靠指数 $0$ 定义了一类非标准的浮点数字。非标准的浮点数字的格式为:

\[\pm 0.b_1b_2\cdots b_{52}\times 2^{-1022}\notag\]

⚠️ 注意:在非标准浮点数格式中,虽然指数为 $-1022$,但实际上指数的机器表示均为0。在这种定义格式下,那些(试图)标准化后指数满足 $-1022-52\le p\le-1022-1$ 的数字被定义为异常浮点数字

异常浮点数字的存在,使得数字的表示范围得到了扩展,使最小可表达数字为 $2^{-52}\times 2^{-1022}=2^{-1074}$ ,它所对应的机器字为

\[0\vert000\ 0000\ 0000\vert0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0001\notag\]

我们必须理解最小可表达数字 $2^{-1074}$ 和机器精度 $\varepsilon_{mach}=2^{-52}$ 之间的差异。在计算机中,许多在机器精度 $\varepsilon_{mach}=2^{-52}$ 以下的数字其实是机器可表达的,但是在 $2^{-1074}$ 以下的双精度数字完全不能被表示(它们的数位均为0,即为数字 0)。

异常数字中最重要的是数字 $0$ ,实际上包含 $+0$ 和 $-0$ ,在实际计算中它们被看作两个相同的实数,它们的机器表达分别为:

\[\begin{align*} &0\vert000\ 0000\ 0000\vert0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\\ &1\vert000\ 0000\ 0000\vert0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000 \end{align*}\]

同样,我们在 MATLAB 中进行验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 >> num2hex(2^(-1074))
 ans =
     '0000000000000001'
     
 >> num2hex(2^(-1077))
 ans =
     '0000000000000000'
     
 >> num2hex(2^(-1031))
 ans =
     '0000080000000000'
 
 >> num2hex(5*2^(-1031))
 ans =
     '0000280000000000'
 
 >> num2hex(+0)
 ans =
     '0000000000000000'
     
 >> num2hex(-0)
 ans =
     '8000000000000000'


实例:将十进制数转换为机器表示

根据二进制的转换方式,并考虑到IEEE 754浮点数标准所要求的(1)标准化(或者非标准化)(2)拟合,我们就可以写出所有数字的符合IEEE 754标准的机器表示。为了充分体现出上述过程,分别举出将十进制数转换为机器表示的例子,并且在MATLAB中进行验证。

标准浮点数的机器表示

例:将 $(0.1)_{10}$ 转换为机器表示。


根据上述十进制向二进制的转换规则,可以得到

\[(0.1)_{10}=(0.0\overline{0011})_2\notag\]

将 $(0.0\overline{0011})_2$ 左对齐(即标准化)可以得到

\[\textcolor{red}{+}1.\textcolor{blue}{1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001}\ 1001\cdots\times 2^{\textcolor{green}{-4}}\notag\]

根据IEEE 754标准所采用的默认的舍入规则

\[\textcolor{red}{+}1.\textcolor{blue}{1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1010}\ \times 2^{\textcolor{green}{-4}}\notag\]

将指数加上双精度的指数偏差 $2^{10}-1=1023$

\[\textcolor{red}{+}1.\textcolor{blue}{1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1010}\ \times 2^{\textcolor{green}{1019}}\notag\]

按照机器表示方法,可以写成

\[\textcolor{red}{0}\textcolor{green}{011\ 1111\ 1011}\ \textcolor{blue}{1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1001\ 1010}\notag\]

将其转换为十六进制

\[\mathrm{3fb999999999999a}\notag\]

在 MATLAB 中进行验证:

1
2
3
>> num2hex(0.1)
ans =
    '3fb999999999999a'

异常浮点数的机器表示

例:将 $5\times2^{-1037}$ 转换为机器表示。


由于指数部分 $-1037$ 超过了 $-1022\sim 1023$ 的表示范围,因此该数字的浮点数一定是异常浮点数(指数位串均为0)。将数字 $5\times2^{-1037}$ 写作非标准浮点数格式:

\[\begin{align*} 5\times2^{-1037}&=(5)_{10}\times2^{-15}\times 2^{-1022}\\ &=(101)_2\times2^{-15}\times 2^{-1022}\\ &=(0.101)_2\times2^{-12}\times 2^{-1022} \end{align*}\]

因此,它的机器表示为:

\[\textcolor{red}{0}\textcolor{green}{000\ 0000\ 0000}\ \textcolor{blue}{0000\ 0000\ 0000\ 1010\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000}\notag\]

将其转换为二进制数

\[\mathrm{000000a000000000}\notag\]

在 MATLAB 中进行验证

1
2
3
>> num2hex(5*2^(-1037))
ans =
    '000000a000000000'


相当于,不等于

上面提到,在双精度计算机中,最小的可以用机器表示的数是 $2^{-1074}$,它是计算机中是最接近 0 的数字,在实际应用中我们完全可以认为它相当于 0 ,但是它在计算机中等于 0 吗?

还是在 MATLAB 中进行验证

1
2
3
4
5
6
7
8
9
10
11
12
>> num2hex(2^(-1074))
ans =
    '0000000000000001'

>> num2hex(0)
ans =
    '0000000000000000'

>> 2^(-1074) == 0
ans =
  logical
   0

可以看到,MATLAB 认为 $2^{-1074}$ 不等于 $0$。

由此得到的启示是,编程中的 “ == ” 逻辑运算符是一个非常严格的判断条件。如果在判断语句中使用 “ == ” 而没有注意到这样的细节,经常会遇到莫名奇妙的结果,而其实程序本身没有问题,只是没有想到计算机本身的特性。


References

[1] Sauer T. 数值分析(原书第2版). 北京: 机械工业出版社, 2014.10(2021.1重印).

[2] Kahan W. IEEE standard 754 for binary floating-point arithmetic[J]. Lecture Notes on the Status of IEEE, 1996, 754(94720-1776): 11.