Python浮点算术:争议和限制

论坛 期权论坛     
选择匿名的用户   2021-5-23 01:16   100   0
<div class="blogpost-body" id="cnblogs_post_body">
<p>浮点数在计算机硬件中表示为以 2 为基数(二进制)的小数。举例而言,十进制的小数</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.125</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>等于 1/10 &#43; 2/100 &#43; 5/1000 ,同理,二进制的小数</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.001</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>等于0/2 &#43; 0/4 &#43; 1/8。这两个小数具有相同的值,唯一真正的区别是第一个是以 10 为基数的小数表示法,第二个则是 2 为基数。</p>
<p>不幸的是,大多数的十进制小数都不能精确地表示为二进制小数。这导致在大多数情况下,你输入的十进制浮点数都只能近似地以二进制浮点数形式储存在计算机中。</p>
<p>用十进制来理解这个问题显得更加容易一些。考虑分数 1/3 。我们可以得到它在十进制下的一个近似值</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.3</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>或者,更近似的,:</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.33</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>或者,更近似的,:</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.333</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>以此类推。结果是无论你写下多少的数字,它都永远不会等于 1/3 ,只是更加更加地接近 1/3 。</p>
<p>同样的道理,无论你使用多少位以 2 为基数的数码,十进制的 0.1 都无法精确地表示为一个以 2 为基数的小数。 在以 2 为基数的情况下, 1/10 是一个无限循环小数</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">0.0001100110011001100110011001100110011001100110011...</pre>
   </div>
   <p> </p>
  </div>
</div>
<p>在任何一个位置停下,你都只能得到一个近似值。因此,在今天的大部分架构上,浮点数都只能近似地使用二进制小数表示,对应分数的分子使用每 8 字节的前 53 位表示,分母则表示为 2 的幂次。在 1/10 这个例子中,相应的二进制分数是 <code class="docutils literal notranslate"><span class="pre">3602879701896397 <span class="pre">/ <span class="pre">2 <span class="pre">** <span class="pre">55</span></span></span></span></span></code> ,它很接近 1/10 ,但并不是 1/10 。</p>
<p>大部分用户都不会意识到这个差异的存在,因为 Python 只会打印计算机中存储的二进制值的十进制近似值。在大部分计算机中,如果 Python 想把 0.1 的二进制对应的精确十进制打印出来,将会变成这样</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">&gt;&gt;&gt; 0.1
0.1000000000000000055511151231257827021181583404541015625</pre>
   </div>
   <p> </p>
   <br>
   <pre class="blockcode"></pre>
  </div>
</div>
<p>这比大多数人认为有用的数字更多,因此<a href="https://www.yuanrenxue.com/">Python</a>通过显示舍入值来保持可管理的位数</p>
<div class="highlight-python3 notranslate">
  <div class="highlight">
   <div class="cnblogs_code">
    <pre class="blockcode">&gt;&gt;&gt; 1 / 10
0.1</pre>
   </div>
   <p> </p>
   <br>
   <pre class="blockcode"></pre>
  </div>
</div>
<p>牢记,即使输出的结果看起来好像就是 1/10 的精确值,实际储存的值只是最接近 1/10 的计算机可表示的二进制分数。</p>
<p>有趣的是,有许多不同的十进制数共享相同的最接近的近似二进制小数。例如, <code class="docutils literal notranslate"><span class="pre">0.1</span></code> 、 <code class="docutils literal notranslate"><span class="pre">0.10000000000000001</span></code> 、 <code class="docutils literal notranslate"><span class="pre">0.1000000000000000055511151231257827021181583404541015625</span></code> 全都近似于 <code class="docutils literal notranslate"><span class="pre">3602879701896397 <span class="pre">/ <span class="pre">2 <span class="pre">** <span class="pre">55</span></span></span></span></span></code> 。由于所有这些十进制值都具有相同的近似值,因此可以显示其中任何一个,同时仍然保留不变的 <code class="docutils literal notranslate"><span class="pre">eval(repr(x)) <span class="pre">&#61;&#61; <span class="pre">x</span></span></span></code>。</p>
<p>在历史上,Python 提示符和内置的 <code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code> 函数会选择具有 17 位有效数字的来昶
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP