{"id":1007,"date":"2021-04-03T18:48:12","date_gmt":"2021-04-03T21:48:12","guid":{"rendered":"http:\/\/www.galirows.com.br\/meublog\/programacao\/?p=1007"},"modified":"2021-06-18T11:00:37","modified_gmt":"2021-06-18T14:00:37","slug":"precisao-numero-flutuante-c","status":"publish","type":"post","link":"http:\/\/www.galirows.com.br\/meublog\/programacao\/precisao-numero-flutuante-c\/","title":{"rendered":"Sobre a precis\u00e3o de n\u00fameros flutuantes em C"},"content":{"rendered":"\n<p>Quando se utilizam n\u00famero de ponto flutuante (<em>float<\/em>) \u00e9 importante considerar quest\u00f5es de precis\u00e3o e arredondamento dos valores. A precis\u00e3o nos c\u00e1lculos utilizando valores de ponto flutuante pode gerar resultados inesperados.<\/p>\n\n\n\n<p>\u00c9 preciso observar que um n\u00famero decimal, seja um valor inteiro ou um valor <em>float<\/em>, possui representa\u00e7\u00e3o bin\u00e1ria no computador. Ou seja, o n\u00famero \u00e9 convertido da base decimal para a bin\u00e1ria. Embora essa transforma\u00e7\u00e3o consiga representar precisamente os valores inteiros, ela n\u00e3o \u00e9 precisa com valores <em>float<\/em>.<\/p>\n\n\n\n<p>Por exemplo, um valor <em>float <\/em>decimal .1 transformado para bin\u00e1rio \u00e9 .0001100110011 (com uma d\u00edzima peri\u00f3dica 0011 que se repete infinitamente). Portanto, o valor n\u00e3o pode ser representado precisamente.<\/p>\n\n\n\n<p>Utilizo o c\u00f3digo a seguir para ilustrar a quest\u00e3o da precis\u00e3o. Veja que no c\u00f3digo realizei a divis\u00e3o 1\/3.0 e n\u00e3o 1\/3, pois a divis\u00e3o de um n\u00famero interior por outro n\u00famero inteiro, na linguagem C, resulta em um valor inteiro. Para testar online os c\u00f3digos disponibilizados nesse post acesse <a href=\"https:\/\/ideone.com\/TmCCaN\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/ideone.com\/TmCCaN<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">int main() {\n    printf(\"%f\\n\", 1\/3.0);\n    printf(\"%f\\n\", 2\/3.0);\n    printf(\"%f\\n\", 1\/3.0 + 2\/3.0);\n    printf(\"%f\\n\", 1\/3.0 + 1\/3.0 + 1\/3.0);\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Sabemos que a divis\u00e3o de 1\/3.0 e 2\/3.0 gera, respectivamente, as d\u00edzimas peri\u00f3dicas 0,33333333333&#8230; e 0,6666666666&#8230;. Ou seja, os valores ap\u00f3s a v\u00edrgula se repetem infinitamente. Um valor <em>float <\/em>\u00e9 representado com apenas 6 casas depois da v\u00edrgula e com isso o primeiro <em>printf <\/em>mostra o valor 0.333333 (um truncamento do valor da d\u00edzima peri\u00f3dica com 6 d\u00edgitos ap\u00f3s a v\u00edrgula). <\/p>\n\n\n\n<p>O terceiro <em>printf <\/em>mostra o resultado da soma de 1\/3.0 e 2\/3.0. Se for considerado o truncamento de 2\/3.0, o valor esperado seria 0.666666 e a soma das duas divis\u00f5es seria 0.999999, mas isso n\u00e3o se confirma com o terceiro <em>printf<\/em>, que mostra que o valor \u00e9 1.000000 (o que \u00e9 esperado pois 1\/3 + 2\/3 \u00e9 igual a 1 inteiro).   <\/p>\n\n\n\n<p>Veja que o segundo <em>printf <\/em>mostra o valor 0.666667, um arredondamento do valor correto. Com isso, a soma do terceiro <em>printf <\/em>\u00e9 o resultado de 0.333333 + 0.666667, que resulta em 1.000000, o que parece responder a quest\u00e3o. Mas veja que o quarto <em>printf<\/em>, que soma 0.333333 + 0.333333 + 0.333333 tamb\u00e9m resulta em 1.000000.<\/p>\n\n\n\n<p>Sendo assim, \u00e9 importante n\u00e3o presumir resultados precisos quando se utilizam n\u00fameros <em>float<\/em>. Ent\u00e3o, cuidado em comparar valores <em>float <\/em>quanto sua igualdade. Para ilustrar essa quest\u00e3o trago dois exemplos.<\/p>\n\n\n\n<p>Como primeiro exemplo para ilustrar como n\u00e3o devemos presumir resultados quando utilizamos <em>float<\/em>, trago o c\u00f3digo a seguir. Uma vez que sabemos que 1\/3.0 resulta em 0.333333 \u00e9 esperado que a compara\u00e7\u00e3o realizada no <em>if <\/em>resulte <em>true<\/em>, mas isso n\u00e3o acontece e com isso o resultado da execu\u00e7\u00e3o do c\u00f3digo n\u00e3o mostrar\u00e1 o <em>printf <\/em>com a palavra &#8220;Entrou&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">int main() {\n    if (0.333333 == 1\/3.0) {\n        printf(\"Entrou\");\n    }\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Como segundo exemplo trago uma compara\u00e7\u00e3o utilizando vari\u00e1veis <em>double <\/em>e <em>float<\/em>. Veja que a \u00fanica diferen\u00e7a dos dois trechos de c\u00f3digo \u00e9 que as vari\u00e1veis <em>soma1 <\/em>e <em>soma2 <\/em>s\u00e3o declaradas com tipos diferentes. Para ambas as vari\u00e1veis eu somo 30 vezes 1\/3.0 (somo 10 vezes 1\/3.0+1\/3.0+1\/3.0). O resultado matem\u00e1tico esperado \u00e9 o valor 10.0, mas apenas a vari\u00e1vel <em>soma2<\/em>, que \u00e9 tipo <em>double <\/em>e com isso com maior precis\u00e3o, consegue realmente alcan\u00e7ar esse valor.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">int main() {\n    float soma1 = 0;\n    for(int i=0; i &lt; 10*3; i++) {\n        soma1+= 1\/3.0;\n    }\n    printf(\"%f \\n\", soma1);\n\n    double soma2 = 0;\n    for(int i=0; i &lt; 10*3; i++) {\n        soma2+= 1\/3.0;\n    }\n    printf(\"%f \\n\", soma2);\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Acho que essa quest\u00e3o de precis\u00e3o dos valores de ponto flutuante merece mais explica\u00e7\u00f5es, o que pretendo fazer no futuro.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quando se utilizam n\u00famero de ponto flutuante (float) \u00e9 importante considerar quest\u00f5es de precis\u00e3o e arredondamento dos valores. A precis\u00e3o nos c\u00e1lculos utilizando valores de ponto flutuante pode gerar resultados inesperados. \u00c9 preciso observar que um n\u00famero decimal, seja um valor inteiro ou um valor float, possui representa\u00e7\u00e3o bin\u00e1ria no computador. Ou seja, o n\u00famero [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1007","post","type-post","status-publish","format-standard","hentry","category-c"],"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/posts\/1007","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/comments?post=1007"}],"version-history":[{"count":7,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/posts\/1007\/revisions"}],"predecessor-version":[{"id":1032,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/posts\/1007\/revisions\/1032"}],"wp:attachment":[{"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/media?parent=1007"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/categories?post=1007"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/programacao\/wp-json\/wp\/v2\/tags?post=1007"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}