-
Notifications
You must be signed in to change notification settings - Fork 25
/
ch14s04.html
5 lines (5 loc) · 9.03 KB
/
ch14s04.html
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>4. 浮点数</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Linux C编程一站式学习" /><link rel="up" href="ch14.html" title="第 14 章 计算机中数的表示" /><link rel="prev" href="ch14s03.html" title="3. 整数的加减运算" /><link rel="next" href="ch15.html" title="第 15 章 数据类型详解" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. 浮点数</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch14s03.html">上一页</a> </td><th width="60%" align="center">第 14 章 计算机中数的表示</th><td width="20%" align="right"> <a accesskey="n" href="ch15.html">下一页</a></td></tr></table><hr /></div><div class="sect1" lang="zh-cn" xml:lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id2754181"></a>4. 浮点数</h2></div></div></div><p>浮点数在计算机中的表示是基于科学计数法(Scientific Notation)<a id="id2754193" class="indexterm"></a>的,我们知道32767这个数用科学计数法可以写成3.2767×10<sup>4</sup>,3.2767称为尾数(Mantissa,或者叫Significand)<a id="id2754206" class="indexterm"></a><a id="id2754214" class="indexterm"></a>,4称为指数(Exponent)<a id="id2754223" class="indexterm"></a>。浮点数在计算机中的表示与此类似,只不过基数(Radix)<a id="id2754232" class="indexterm"></a>是2而不是10。下面我们用一个简单的模型来解释浮点数的基本概念。我们的模型由三部分组成:符号位、指数部分(表示2的多少次方)和尾数部分(小数点前面是0,尾数部分只表示小数点后的数字)。</p><div class="figure"><a id="id2752523"></a><p class="title"><b>图 14.6. 一种浮点数格式</b></p><div class="figure-contents"><div><img src="images/number.float.png" alt="一种浮点数格式" /></div></div></div><br class="figure-break" /><p>如果要表示17这个数,我们知道17=17.0×10<sup>0</sup>=0.17×10<sup>2</sup>,类似地,17=(10001)<sub>2</sub>×2<sup>0</sup>=(0.10001)<sub>2</sub>×2<sup>5</sup>,把尾数的有效数字全部移到小数点后,这样就可以表示为:</p><div class="figure"><a id="id2752563"></a><p class="title"><b>图 14.7. 17的浮点数表示</b></p><div class="figure-contents"><div><img src="images/number.float17.png" alt="17的浮点数表示" /></div></div></div><br class="figure-break" /><p>如果我们要表示0.25就遇到新的困难了,因为0.25=1×2<sup>-2</sup>=(0.1)<sub>2</sub>×2<sup>-1</sup>,而我们的模型中指数部分没有规定如何表示负数。我们可以在指数部分规定一个符号位,然而更广泛采用的办法是使用偏移的指数(Biased Exponent)<a id="id2752592" class="indexterm"></a>。规定一个偏移值,比如16,实际的指数要加上这个偏移值再填写到指数部分,这样比16大的就表示正指数,比16小的就表示负指数。要表示0.25,指数部分应该填16-1=15:</p><div class="figure"><a id="id2752604"></a><p class="title"><b>图 14.8. 0.25的偏移指数浮点数表示</b></p><div class="figure-contents"><div><img src="images/number.biasfloat025.png" alt="0.25的偏移指数浮点数表示" /></div></div></div><br class="figure-break" /><p>现在还有一个问题需要解决:每个浮点数的表示都不唯一,例如17=(0.10001)<sub>2</sub>×2<sup>5</sup>=(0.010001)<sub>2</sub>×2<sup>6</sup>,这样给计算机处理增加了复杂性。为了解决这个问题,我们规定尾数部分的最高位必须是1,也就是说尾数必须以0.1开头,对指数做相应的调整,这称为正规化(Normalize)<a id="id2752639" class="indexterm"></a>。由于尾数部分的最高位必须是1,这个1就不必保存了,可以节省出一位来用于提高精度,我们说最高位的1是隐含的(Implied)<a id="id2752649" class="indexterm"></a>。这样17就只有一种表示方法了,指数部分应该是16+5=21=(10101)<sub>2</sub>,尾数部分去掉最高位的1是0001:</p><div class="figure"><a id="id2754520"></a><p class="title"><b>图 14.9. 17的正规化尾数浮点数表示</b></p><div class="figure-contents"><div><img src="images/number.normalfloat17.png" alt="17的正规化尾数浮点数表示" /></div></div></div><br class="figure-break" /><p>两个浮点数相加,首先把小数点对齐然后相加:</p><div class="figure"><a id="id2754538"></a><p class="title"><b>图 14.10. 浮点数相加</b></p><div class="figure-contents"><div><img src="images/number.addfloat.png" alt="浮点数相加" /></div></div></div><br class="figure-break" /><p>由于浮点数表示的精度有限,计算结果末尾的10两位被舍去了。做浮点运算时要注意精度损失(Significance Loss)<a id="id2754556" class="indexterm"></a>问题,有时计算顺序不同也会导致不同的结果,比如11.0010000+0.00000001+0.00000001=11.0010000+0.00000001=11.0010000,后面加的两个很小的数全被舍去了,没有对计算结果产生任何影响,但如果调一下计算顺序它们就能影响到计算结果了,0.00000001+0.00000001+11.0010000=0.00000010+11.0010000=11.0010001。再比如128.25=(10000000.01)<sub>2</sub>,需要10个有效位,而我们的模型中尾数部分是8位,算上隐含的最高位1一共有9个有效位,那么128.25的浮点数表示只能舍去末尾的1,表示成(10000000.0)<sub>2</sub>,其实跟128相等了。在<a class="xref" href="ch04s02.html#cond.ifelse">第 2 节 “if/else语句”</a>讲过浮点数不能做精确比较,现在读者应该知道为什么不能精确比较了。</p><p>整数运算会产生溢出,浮点运算也会产生溢出,浮点运算的溢出也分上溢和下溢两种,但和整数运算的定义不同。假设整数采用8位2's Complement表示法,取值范围是-128~127,如果计算结果是-130则称为下溢,计算结果是130则称为上溢。假设按本节介绍的浮点数表示法,取值范围是-(0.111111111)<sub>2</sub>×2<sup>15</sup>~(0.111111111)<sub>2</sub>×2<sup>15</sup>,如果计算结果超出这个范围则称为上溢;如果计算结果未超出这个范围但绝对值太小了,在-(0.1)<sub>2</sub>×2<sup>-16</sup>~(0.1)<sub>2</sub>×2<sup>-16</sup>之间,那么也同样无法表示,称为下溢。</p><p>浮点数是一个相当复杂的话题,不同平台的浮点数表示和浮点运算也有较大差异,本节只是通过这个简单的模型介绍一些基本概念而不深入讨论,理解了这些基本概念有助于你理解浮点数标准,目前业界广泛采用的符点数标准是由IEEE(Institute of Electrical and Electronics Engineers)<a id="id2754656" class="indexterm"></a>制定的IEEE 754<a id="id2754663" class="indexterm"></a>。</p><p>最后讨论一个细节问题。我们知道,定义全局变量时如果没有Initializer就用0初始化,定义数组时如果Initializer中提供的元素不够那么剩下的元素也用0初始化。例如:</p><pre class="programlisting">int i;
double d;
double a[10] = { 1.0 };</pre><p>“<span class="quote">用0初始化</span>”的意思是变量<code class="literal">i</code>、变量<code class="literal">d</code>和数组元素<code class="literal">a[1]~a[9]</code>的所有字节都用0填充,或者说所有bit都是0。无论是用Sign and Magnitude表示法、1's Complement表示法还是2's Complement表示法,一个整数的所有bit是0都表示0值,但一个浮点数的所有bit是0一定表示0值吗?严格来说不一定,某种平台可能会规定一个浮点数的所有bit是0并不表示0值,但<a class="xref" href="bi01.html#bibli.rationale" title="Rationale for International Standard - Programming Languages - C">[<abbr class="abbrev">C99 Rationale</abbr>]</a>第6.7.8节的条款25提到:As far as the committee knows, all machines treat all bits zero as a representation of floating-point zero. But, all bits zero might not be the canonical representation of zero. 因此在绝大多数平台上,一个浮点数的所有bit是0就表示0值。</p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch14s03.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="ch14.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="ch15.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">3. 整数的加减运算 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 15 章 数据类型详解</td></tr></table></div></body></html>