<!--
 Introdução à Programação - 2017 - Prof. Leoônidas de Oliveira Brandão
 Introdução aos números em ponto flutuantes
 LInE (Laboratory of Informatics in Education) - http://www.usp.br/line
 IME - USP
 Material didático
 Pode usar livrevemente este material para fins não comerciais, devendo sempre fazer referência à autoria.
 Sugestões/apontamento são bem vindos: leo@ime.usp.br (favor indicar no assunto "material de introducao 'a programacao")
 Prof. Leônidas de Oliveira Brandão
 http://www.ime.usp.br/~leo
 http://line.ime.usp.br
 http://www.matemtica.br

 href="#" id="url1" onclick="trocaPagina('introducao_inteiros.html')"

-->

  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
  <meta name='keywords' content='mac0122, material, professores, leonidas de oliveira brandao'>
  <link rel='stylesheet' type='text/css' href='css_img_js_conf/all.css'>
  <link rel='stylesheet' type='text/css' href='css_img_js_conf/line_introducao_programacao.css'>
  <script src="css_img_js_conf/defineLInE.js"></script> <!-- para referencias 'a documentos internos -->

<div class="pagina">


<p class="secao">Introdução aos números em ponto flutuantes</p>

<p>
  Nesta seção examinaremos resumidamente como o computador representa números reais.
  A seção seguinte foi redigida para aqueles que desejam conhecer mais, estudando-a pode-se compreender a matemática associada
  ao conteito de representação de números em um computador digital e a razão do termo <b>ponto flutuante</b>.
</p>


<p>
  Normalmente deve-se utilizar um número fixo de <i>bits</i> para representar cada número.
  Por exemplo, se determinado computador usar apenas 2 <i>bytes</i> (ou 16 <i>bits</i>) para
  representar um real e convencionar-se que o primeiro <i>byte</i> armazena a parte inteira e o segundo
  <i>byte</i> a parte decimal, teríamos uma variabilidade pequena de números.
  Como visto no texto
  <!-- a href="introducao_inteiros.html" title="examinar o texto sobre inteiros">introdutório sobre inteiros</a -->
  <a href="#" onclick="trocaPagina('introducao_inteiros.html')" title="examinar o texto sobre inteiros">introdutório sobre inteiros</a>,
  com 8 <i>bits</i>, teríamos (simplificadamente) desde o <i>11111111</i> (primeiro <i>bit</i> indica negativo) até o
  <i>01111111</i>, que em decimal seriam desde <i>-127</i> até o <i>127</i>, pois
  <center>
    <i>
      1111111<sub>2</sub> = 
      2<sup>7</sup> + 2<sup>6</sup> + 2<sup>5</sup> + 2<sup>4</sup> + 2<sup>3</sup> + 2<sup>2</sup> + 2<sup>1</sup> + 2<sup>0</sup> =
      128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 &nbsp; &nbsp; (1)
    </i>
  </center>    
  <!-- 
  na verdade, usando a técnica prática de <i>complemento de dois</i>, iria desde <i>-128</i> até o <i>127</i>
  -->
</p>

<center><p>[
  <a href="#pontofixo" title="Estudar este outro modelo de representação de real para entender a razão do uso de ponto flutuante">Ponto fixo</a> | 
  <a href="#pontoflutuante" title="Estudar os fundamentos do uso de ponto flutuante para representar reais">Ponto flutuante (PF)</a> | 
  <a href="#pontoflutuanteSimples" title="se estiver interessado em uma explicação super simplificada, começe por aqui">PF super simplificado</a> | 
  <a href="#exemplo" title="Um exmplo simplificado da representação em ponto flutuante">Exemplo</a> | 
  <a href="#erro" title="Erros numéricos devido à representação em ponto flutuante">Erros</a> |
  <a href="#io" title="Exemplos para impressões mais interessantes de ponto flutuante">Entrada/saída</a></a>
 ]</p>
</center>



<p>
<a name="pontofixo"></a>
</p>
<span style="color: #0055AA">Um primeiro modelo (ineficiente) para representar valores reais: ponto fixo</span>

<p>
  Para apresentar o conceito que interessa, de <i>ponto flutuante</i>, apresentarei sua contra-parte, como seria uma representação em <b>ponto fixo</b>.
  Vamos continuar usando 2 <i>bytes</i> (logo 16 <i>bits</i>) e considerar 3 agrupamentos:
  P1. o primeiro <i>bit</i> para representar o sinal do número (<i>s=0</i> para positivo e <i>s=1</i> para negativo);
  P2. os próximos 7 como a parte "decimal" (após vírgula decimal); e
  P3. os últimos 8 <i>bits</i> para o valor inteiro do número.
</p>

<p>
  Assim, para obter o maior valor positivo que poderia ser representado nesta notação, deveríamos deixar o primeiro <i>bit</i> em zero
  (para ser positivo) e todos os seguintes "ligados": <tt>0 1111111 11111111</tt> (deixei espaço em branco para indicar os 3 agrupamentos).
  <br/>
  Assim, a parte "decimal" P2 (<tt>1111111</tt>) corresponde em decimal:
  <center>
    <i>2<sup>-1</sup> + 2<sup>-2</sup> + 2<sup>-3</sup> + 2<sup>-4</sup> + 2<sup>-5</sup> + 2<sup>-6</sup> + 2<sup>-7</sup> =
      0.5 + 0.25 + 0.125 + 0.0625 + 0.03125 + 0.015625 + 0.007812 = 0.992188</i> &nbsp; &nbsp; (2)
  </center><br/>

  Portanto o maior positivo, convertendo para decimal, seria a soma de (1) e (2): &nbsp; <i>255.992188</i>. Desse modo, em <b>ponto fixo</b>:
  <br/>
  <center>
   <i>Tab. 1. Maior e menor positivo que pode-se obter com a representação em <i>ponto fixo</i>
   <br/>
   <table><tr><td>
   &nbsp; &nbsp; &nbsp; - maior valor positivo em binário <tt>00111111 01111111<sub>2</sub></tt> = <i>255.992188</i> em decimal;<br/>
   &nbsp; &nbsp; &nbsp; - menor valor estritamente positivo em binário <tt>00000001 00000000<sub>2</sub></tt> = <i>0.007812</i> em decimal.
   </td></tr></table>
  </center>
</p>
   
<p>
<a name="pontoflutuante"></a>
<span style="color: #0055AA">Um modelo de representação para real mais eficiente: ponto flutuante</span>
</p>

<p>
  Uma alternativa mais eficiente e amplamente utilizada na prática é a representação em <b style="color: #0000aa;">ponto flutuante</b>.
  Nessa representação também quebramos o número em três agrupamentos, a primeira sendo o <b>sinal</b> <i>s</i>, a segunda
  o <b style="color: #0000aa;">expoente</b> <i>e</i>
  e a terceira sendo <b style="color: #0000aa;">mantissa</b> <i>m</i>, assim o valor do número seria <i>s x m x b<sup>e</sup></i>.
  Se a mantissa tiver <i>p</i> dígitos, o número é:
  <tt>s x d<sub>0</sub>d<sub>1</sub>...d<sub>p-1</sub> x b<sup>e</sup></tt>.
</p>

<p><center>
 <img src="img/img_real_ponto_fixo.png" title="Imagem representando a memória com representação de ponto fixo"/>
 <br/>
 <i>Fig. 1. Representação em memória para <i>ponto fixo</i> para representar reais, com 7 <i>bits</i> de expoente e 8 <i>bits</i> para mantissa.
</i>
</center></p>

<p>
  Assim, nota-se que a diferença entre a representações em <i>ponto flutuante</i> e em <i>ponto fixo</i> é o tratamento do segundo agrupamento.
  Para poder comparar ambas as representações, vamos novamente supor um computador com reais usando apenas 2 <i>bytes</i>.
</p>

<p>
  Desse modo, o <i>maior real positivo</i> nesse <i>ponto flutuante</i> é obtido usando a maior potência e maior mantissa possiveis, respectivamente
  <i>0111111</i> e <i>11111111</i>, que em decimal são,
  <center>
    2<sup>6</sup> + 2<sup>5</sup> + 2<sup>4</sup> + 2<sup>3</sup> + 2<sup>2</sup> + 2<sup>1</sup> + 2<sup>0</sup> =
    64 + 32 + 16 + 8 + 4 + 2 + 1 = 127 &nbsp; &nbsp; (3)
    <br/>    
    2<sup>8</sup> + 2<sup>7</sup> + 2<sup>6</sup> + 2<sup>5</sup> + 2<sup>4</sup> + 2<sup>3</sup> + 2<sup>2</sup> + 2<sup>1</sup> + 2<sup>0</sup> =
    256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 511 &nbsp; &nbsp; (4)
  </center>
  <br/>
  Portanto, o <i>maior real positivo</i> nesse <i>ponto flutuante</i> é <i>511 x 2<sup>127</sup></i>, um número gigantesto
  (maior que <i title="170 141 183 000 000 002 920 328 542 032 742 055 936.0">1.70141183 x 10<sup>38</sup></i>).
  <!--
               2^127 = 170 141 183 460 469 231 731 687 303 715 884 105 728
  1.70141183 * 10^38 = 170 141 183 000 000 002 920 328 542 032 742 055 936.000000
  1.70141184 * 10^38 = 170 141 183 999 999 980 188 862 898 952 269 201 408.000000
  -->
</p>

<p>
  De forma análoga, podemos computar o <i>menor valor estritamente positivo</i> que conseguimos com essa representação.
  Como são 7 <i>bits</i> para expoente e 8 <i>bits</i> para a mantissa, devemos pegar no agrupamento P2 a sequência
  <i>1111111</i> (maior potência negativa possível) e no agrupamento P3 o menor valor positivo, que seja maior que zero, portanto <i>00000001</i>.
  Convertendo <i title="-2^6">1111111</i> para decimal, temos o valor <i>-64</i>, logo o menor positivo é:
  <i>2<sup>-64</sup></i> que é aproximadamente <i>5.42101086243e-20</i> (tremendamente pequeno).
</p>

<p>
  Portanto o maior positivo e o menor , convertendo para decimal, seria a soma de (1) e (2): &nbsp; <i>255.992188</i>. Desse modo, em <b>ponto fixo</b>:
  <center>
   <i>Tab. 2. Maior e menor positivo que pode-se obter com a representação em <i>ponto flutuante</i>
   <br/>
   <table><tr><td>
   &nbsp; &nbsp; &nbsp; - maior valor positivo em binário <tt>00111111 01111111<sub>2</sub></tt> > <i>1.70141183 * 10<sup>38</sup></i> em decimal;<br/>
   &nbsp; &nbsp; &nbsp; - menor valor estritamente positivo em binário <tt>1111111 00000001<sub>2</sub></tt> ~=
                          <i title="notação científica: 3e-20 equivale a 3*(2.7183^-20)">5.42101086243e-20</i> em decimal.
   </td></tr></table>
  </center>
</p>

<p>
  Comparando os resultados de <i>ponto flutuante</i> com <i>ponto fixo</i>, tabelas 1 e 2, percebemo que
  <i>ponto flutuante</i> produz resultados muito melhores em termos de capacidade de "simular" os números reais.
</p>


<p>
<a name="pontoflutuantesimples"><span style="color: #0050A0">Representação em ponto flutuante</span></a>
</p>

<p>
  Esta técnica de representação é a mais utilizada nos computadores, ela utiliza um <em>bit</em> para sinal,
  uma quantidade pequena de <em>bits</em> para o expoente e uma quantidade maior de <em>bits</em> para a parte "principal" do
  número. Em um dos padrões de representação (IEEE 754) o número é representado com 11 <em>bits</em> para o expoente e
  52 <em>bits</em> para a mantissa.
</p>


<p>
<a name="exemplo"><span style="color: #0050A0">Exemplo de representação em ponto flutuante</span></a>
</p>

<p>
  Para ilustrar o funcionamento de ponto flutuante, suponha um computador que use representação em decimal
  (os computadores na verdade usam base <i>binária</i>), tendo apenas 3 dígitos para mantissa e o expoente sendo de <i>-4</i> até <i>-4</i>, assim
  teríamos <tt>p=3</tt> e <tt>-4<u><</u>e<u><</u>4</tt>.
</p>

<p>
  Deste modo, o maior valor real que pode ser representado seria o <tt>999000</tt>, pois tomando a maior mantissa e maior
  expoente, teríamos <tt>10<sup>3</sup> x 999 = 999000</tt>.
</p>

<p>
  Já o menor valor estritamente positivo que conseguiríamos seria o <tt>0.001</tt>, pois tomando a menor mantissa positiva e menor expoente possível (-3),
  teríamos <tt>10<sup>-3</sup> x 1 = 0.001</tt>.
</p>
        
<p>
  Desse modo, nesse computador simples, a variação de números "reais" que poderiam ser representados nesse computador, seria:
  <center>
   <i>Tab. 3. Maior e menor positivo que pode-se obter com a representação em <i>ponto flutuante</i> em decimal.
   <br/>
   <table><tr><td>
    &nbsp; &nbsp; &nbsp; - maior valor positivo: <i>999 x 10<sup>3</sup> = 999000<i>;<br/>
    &nbsp; &nbsp; &nbsp; - menor valor estritamente positivo: <i>1 x 10<sup>-3</sup> = 0.001<i>.
   </td></tr></table>
  </center>
</p>



<p>
<a name="erro"><span style="color: #0050A0">Erros numéricos</span></a>
</p>

<!--
que corresponde ao decimal <i>31=2<sup>5</sup>-1</i>, portanto o menor real positivo
seria <i>1 x 10<sup>-31</sup></i> que é um número muito menor que o <i>1/255</i> da representação em <i>ponto fixo</i>.
-->

<p>
A primeira questão que aparece ao tratar números não inteiros no computador digital é a perda de precisão ou os erros numéricos.
Por exemplo, mesmo em notação decimal o valor 1/3 não será representado perfeitamente, ele será registrado com algo semelhante
a <tt>0.3333</tt> (se o computador utilizar 4 dígitos).
</p>

<p>
Um exemplo do problema numérico está ilustrado no exemplo abaixo, quando tentamos imprimir as somas de <tt>0.1</tt>
até <tt>0.9</tt>. Experimente copiar este trecho de código e roder em <em>C</em> ou em <em>Python</em>, você verá
que o algoritmo nunca parará! Isso mesmo, laço infinito, pois como o computador utiliza notação binário e como o decimal
<tt>0.1</tt> em binário corresponde a um binário periódico (como a dízima periódica resultante do <tt>1/3</tt> que é
<tt>0.3...</tt>).
<center>
<i>Tab. 4. Cuidado com a aritmética de ponto flutuante! Nem tudo é o que parece ser...</i>
<br/>
<table class="tbCodeLinCol">
 <tr><th>C </th> <th>Python</th></tr>
 <tr valign="top"><td><table class="tbCode">
   <tr><td><pre>x = 0.1;
while (x!=1.0) {
  <verd>printf</verd>("%f\n", x);
  x += 0.1;
  }
<verd>printf</verd>("Final!\n");</pre></td></tr>
 </table></td>
 <td><table class="tbCode"><pre>x = 0.1
while (x!=1.0) :
  <verd>print</verd>(x)
  x += 0.1
<verd>print</verd>("Final!")</pre></td></tr>
   </table></td></tr>
</table>
</center>
</p>


<p>
<a name="io"><span style="color: #0050A0">Entrada e saída de flutuantes em <i>C</i> e em <i>Python</i></span></a>
</p>

<p>
Em <i>C</i> deve-se utilizar o formatador <tt>%f</tt> para indicar que os <em>bits</em> devem ser tratados como número
em ponto flutuante, enquanto em <i>Python</i> deve-se utilizar a função <tt>float(...)</tt>, como indicado no exemplo
abaixo.
<center>
<i>Tab. 5. Como imprimir números em ponto flutuante.</i>
<br/>
<table class="tbCodeLinCol">
 <tr><th>C </th> <th>Python</th></tr>
 <tr valign="top"><td><table class="tbCode">
   <tr><td><pre><verm>float</verm> x; <cyan>// declaracao de variavel em "ponto flutuante"</cyan>
<verd>scanf</verd>("%f", &x); <cyan>// leia como "ponto flutuante"</cyan>
<verd>printf</verd>("%f\n", x); <cyan>// imprima como "ponto flutuante"</cyan>
<cyan>// Usar formatador %N.kf para usar N posicoes ajustadas 'a direita e k decimais</cyan>
<verd>printf</verd>("Tab.\nx=%3.2f\nx=%3.2f", x, x); <cyan>// imprima com 2 casas decimais</cyan>
</pre></td></tr>
 </table></td>
 <td><table class="tbCode"><pre>x = <verm>float</verm>(<verd>input</verd>()) <cyan># leia e transforme em "ponto flutuante"</cyan>
<verd>print</verd>(x); <cyan># impressao simples</cyan>
<cyan># Util para colocar frases mais "sofisticadas"</cyan>
<verd>print</verd>("x=%f - frases mais \"sofisticadas\"" % x); <cyan># impressoes mais sofisticadas</cyan>
<cyan># Assim e' util para construir tabelas.</cyan>
<verd>print</verd>("Tab.\nx=%3.2f\nx=%3.2f" % (x,x)); <cyan># o \n quebra linha</cyan>

</pre></td></tr>
   </table></td></tr>
</table></center>
</p>

<p>
Aos alunos estudando com a linguagem <i>C</i>, tomem um cuidado adicional: o compilador <i>C</i> aceita utilizar o formatador
de inteiro na leitura e na impressão de uma variável em flutuante. Ele trunca o valor, assim se tiver <tt>float x=1.5;</tt>
e fizer <tt><verd>printf</verd>("x=%d\n", x);</tt>, não haverá erro de compilação e será impresso <tt>x=1</tt>.
</p>


<p>
Uma boa fonte para pesquisar é
examinar o texto na <a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic" title="examinar WikiPedia: floating-point">WikiPedia: floating-point</a>.
<!-- https://en.wikipedia.org/wiki/Single-precision_floating-point_format -->
</p>

  <p class="autoria">
    <a href="https://www.ime.usp.br/~leo" target="_blank" title="seguir para a pagina do prof. Leônidas">Leônidas de Oliveira Brandão</a><br/>
    <a href="http://www.ime.usp.br/~leo" target="_blank" title="seguir para a página do LInE">http://line.ime.usp.br</a>
  </p>

<p class="rodape">
  <b>Alterações</b>:<br/> 
  2020/08/10: novas seções iniciais;<br/>
  2020/04/18: inserido nomes nas tabelas, correcao tab. 1 ("x+=1.0"->"x+=0.1")<br/>
  2017/04/14: primeira versão
</p>

</div>

<script src="css_img_js_conf/defineLInE.js"></script> <!-- function defineEndereco (url1) -->