Visite também: Currículo ·  Efetividade BR-Mac

O que é LinuxDownload LinuxApostila LinuxEnviar notícia


Normatização vs. Realidade: o que considerar certo ou errado na hora H?

“Responda rápido: quanto é 1*(0,5-0,4-0,1)? Para a maioria de nós, zero, mas não para o Microsoft Excel, que considera o resultado como -2,7755*10^-17.

O que aparentemente pode ser considerado um bug apoia-se em uma norma técnica, a IEEE 754, que regulamenta como os programas de computador devem tratar números com ponto flutuante.

Curiosamente, o software livre de cálculos Octave apresenta o mesmo resultado que o Excel e a calculadora do Gnome mostra como resposta -0, o que pode sugerir um arredondamento ou truncamento. E então, quem está certo e quem está errado?”

Enviado por André Machado (andreferreiramachadoΘgmail·com) – referência (tuxtoriais.wordpress.com).


• Publicado por Augusto Campos em 2009-02-03

Comentários dos leitores

Os comentários são responsabilidade de seus autores, e não são analisados ou aprovados pelo BR-Linux. Leia os Termos de uso do BR-Linux.

    Rodrigo Pinheiro Matias (usuário não registrado) em 3/02/2009 às 12:05 pm

    Eu acredito que os dois estão corretos, deve se observar a configuração padrão da celula, e vê como cada uma esta configurada, pois, é um numero tão pequeno quanto eu queria, veja -2*10^-17 ou seja um numero com 17 casa decimais.

    Eri Ramos Bastos (usuário não registrado) em 3/02/2009 às 12:44 pm

    Humm…

    $ bc
    bc 1.06.94
    Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
    This is free software with ABSOLUTELY NO WARRANTY.
    For details type `warranty'.
    1*(0.5-0.4-0.1)
    0
    quit

    Próximo…

    Marcos Alexandre (usuário não registrado) em 3/02/2009 às 12:47 pm

    Pra quem já programou em baixo nível sabe que ponto flutuante na informática é dureza.

    Mas o que me chamou mais a atenção foi a diferença de interface do Office 2007 pro “concorrente”.

    Allan Taborda (usuário não registrado) em 3/02/2009 às 12:51 pm

    A discussão sobre este fenômeno matemático ocorrido no MS Excel iniciou-se em um tópico do Orkut, na comunidade Linux versus Windows:

    http://www.orkut.com.br/Main#CommMsgs.aspx?cmm=18655944&tid=5297825684124574372

    Minha opinião pessoal está no referido tópico.

    Fellype (usuário não registrado) em 3/02/2009 às 1:00 pm

    Rodrigo,
    Falando como Físico, sua resposta seria aceitável pra muitas coisas da vida prática. Dizer que -2,7755*10^-17 é aproximadamente igual a zero parece ser algo razoável. Mas este número, que é muito pequeno, não é zero. E podem atrapalhar alguns cálculos científicos.
    Pra vc ter uma idéia, considere como exemplo o comprimento de onda da luz de um laser de He-Ne (632,8*10^-9 nm). Em alguns cálculos, temos que elevar este número ao quadrado, o que dá 4,0043584*10^-13. Ou seja, se eu tiver que somar a isto o número -2,7755*10^-17, terei afetado minha conta na 4ª casa decimal, o que poderia ser um problema, dependendo do caso.
    Este foi apenas um exemplo. Existem áreas que trabalham com fatores ainda menores que isto.
    Além do mais, se esta conta do excel está errada, pode se imaginar que existam outros erros, quem sabe até piores (já ouvi falar antes de uma coisa parecida).

    Fellype (usuário não registrado) em 3/02/2009 às 1:05 pm

    Aliás, no BrOffice a conta dá 0,00E+00. Independe da configuração da célula…

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 1:17 pm

    E podem atrapalhar alguns cálculos científicos.

    Em sistemas dinâmicos caóticos, essa “pequena” diferença muda totalmente o resultado e a precisão dos seus cálculos. Se você quiser estimar a posição de um corpo celeste daqui alguns anos, esta posição pode ser praticamente qualquer lugar no universo visível…

    Eu nunca li essa norma técnica e minha experiência com cálculo numérico é limitada, mas eu acredito que não deveria haver arredondamentos ou truncagem devido a precisão de ponto flutuante numa expressão estupidamente simples. Essa conta só exige precisão de um digíto significativo! Se você computar primeiro a expressão dentro dos parênteses, na ordem em que ela é dada, você obtém 0 e 1 vezes 0 é 0. Se você computar primeiro a multiplicação por 1, a conta não muda!

    Curiosamente, executem este simples código Javascript no navegador de vocês e vejam o resultado que aparece:

    javascript:document.write(1*(0.5-0.4-0.1));

    Allan Taborda (usuário não registrado) em 3/02/2009 às 1:19 pm

    Marcos Alexandre, a questão da interface não está sendo discutida. Entretanto, eu prefiro a interface do OpenOffice.org, questão de gosto isso…

    Mas o fato é que ambas as planilhas fazem uso da norma ISO 754. Ah, e me parece que o MS Office não implementa totalmente tal norma, embora eu não tenha certeza disso.

    Pelo que dá para ver, o MS Office exibe por padrão um formato não muito amigável para o usuário final, a notação científica. Formatando para valor numérico, o valor que aparece é 0, mas este zero é, na verdade, um valor arredondado do número próximo de zer, mas que não é zero.

    Já o OpenOffice.org, que por padrão apresenta o número formatado como valor numérico, mais amigável para o usuário final, caso a formatação seja alterada para notação científica, o número exibido é zero, no caso, 0,00E+000.

    Humberto (usuário não registrado) em 3/02/2009 às 1:37 pm

    Tentei na calculadora do Gnome e vi o resultado -0. Ao escolher o formato científico para vizualização obtive o resultado: -1,991364889e-59

    $ tcc -run -
    #include <stdio.h>
    int main() {
    printf("%e ", 1*(0.5-0.4-0.1));
    }
    -2.775558e-17
    $ js
    js> 1*(0.5-0.4-0.1)
    -2.7755575615628914e-17
    js>
    $ ghci
    GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer ... linking ... done.
    Loading package base ... linking ... done.
    Prelude> 1*(0.5-0.4-0.1)
    -2.7755575615628914e-17
    Prelude> ^DLeaving GHCi.
    $

    O Python 2.5 apresenta -2.7755575615628914e-17

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 1:42 pm

    A propósito, o Scilab também responde da mesma forma:

    -->1*(0.5-0.4-0.1)
    ans =
    - 2.776D-17

    Pelo que dá para ver, o MS Office exibe por padrão um formato não muito amigável para o usuário final, a notação científica. Formatando para valor numérico, o valor que aparece é 0, mas este zero é, na verdade, um valor arredondado do número próximo de zer, mas que não é zero.

    Já o OpenOffice.org, que por padrão apresenta o número formatado como valor numérico, mais amigável para o usuário final, caso a formatação seja alterada para notação científica, o número exibido é zero, no caso, 0,00E+000.

    Por que notação científica seria “menos amigável para o usuário final”? Notação científica se aprende no Ensino Fundamental. Eu acho mais correto o comportamento do Excel, que não mascara o resultado e mostra o que realmente está contido na célula.

    O que pode ser considerado “menos amigável” seja talvez o fato de o Excel considerar o ano 1900 como um ano bissexto, ou o fato de a função DESV.MÉDIO calcular o número de combinações (n k) ao invés de calcular o desvio médio de uma lista de valores…

    maskd (usuário não registrado) em 3/02/2009 às 1:43 pm

    $ js
    Rhino 1.7 release 1 2008 10 20
    js> t = 3/10;
    0.3
    js> u = 1/10;
    0.1
    js> (3*u - t)/(2*u - t + u);
    2
    js>

    Eduardo Siemann (usuário não registrado) em 3/02/2009 às 2:03 pm

    @Jack Ripoff
    “Eu acho mais correto o comportamento do Excel,”

    Calma vamos pensar matemática simples o valor deve ser 0 mesmo, desde quando 0,5 ou 5/10 menos 0,4 ou 4/10 dá diferente de 1/10?

    EX no java 0.5-0.4 dá 0.09999999999999998 mas o valor correto é 0.1
    ou seja o Excel está errado, ou vão falar qualquer professor de matemática que 5/10-4/10 não dá 1/10?

    posso ser programador usar bits blabla mas matemática básica não foi alterada ainda :)

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 2:11 pm

    Calma vamos pensar matemática simples o valor deve ser 0 mesmo, desde quando 0,5 ou 5/10 menos 0,4 ou 4/10 dá diferente de 1/10?

    EX no java 0.5-0.4 dá 0.09999999999999998 mas o valor correto é 0.1
    ou seja o Excel está errado, ou vão falar qualquer professor de matemática que 5/10-4/10 não dá 1/10?

    Depois me passa o contato da escola onde você fez o curso “Como tirar as coisas do contexto”.
    </sarcasmo>

    Se você reler o meu comentário, vai ver que eu me referia especificamente ao fato de o Excel exibir por padrão o conteúdo da célula em notação científica, em contraste com o Calc que exibe o número arredondado por padrão.

    Além disso, para sua informação, 0,0999… é exatamente igual a 0,1. Eu já fui professor de matemática e se você quiser eu forneço a demonstração algébrica ;).

    (Note no entanto que o resultado fornecido pelo Java foi truncado e arredondado (???) no 16º significativo, não sendo portanto a mesma coisa…)

    I haven’t read the whole thread yet, but I’d like to add a point about OpenOffice: OpenOffice uses wrappers around floating-point operations to correct some round-off errors. That’s why it appears to be “correct”, but in fact, you should be aware that this is not reliable and can hide real user-side bugs. There has been a discussion about this in the French users mailing-list in February/March 2005 (thread “[users-fr] [CALC] Calculs imprécis”).

    Ref.: http://blogs.msdn.com/excel/archive/2007/09/25/calculation-issue-update.aspx

    De fato, o OpenOffice usa wrappers em torno das operações matemáticas, para tentar reduzir os erros de arredondamento causados pelos cálculos com ponto flutuante padrão IEEE 754 (que são feitos pela unidade de ponto flutuante do seu processador, e não implementados por um programa ou outro).

    Fiz uma pesquisa no Google CodeSearch e encontrei que esses wrappers podem ser encontrados no arquivo include/rtl/math.hxx do código do OpenOffice:

    http://www.google.com/codesearch/p?hl=pt-BR#g605e157DJA/OpenOffice.org1.1.2_SDK/include/rtl/math.hxx&q=math%20package:openoffice

    Se quiser simular esse comportamento, utilize o seguinte código:

    #include <cstdio>

    inline bool approxEqual(double a, double b)
    {
    if ( a == b )
    return true;
    double x = a - b;
    return (x < 0.0 ? -x : x)
    < ((a < 0.0 ? -a : a) * (1.0 / (16777216.0 * 16777216.0)));
    }
    inline double approxSub(double a, double b)
    {
    if ( ((a < 0.0 && b 0.0 && b > 0.0)) && approxEqual( a, b ) )
    return 0.0;
    return a - b;
    }
    int main() {
    printf("%e ", 1*(approxSub(approxSub(0.5, 0.4), 0.1)));
    return 0;
    }

    Salve num arquivo approx.cpp, compile e rode:


    $ g++ approx.cpp -o approx
    $ ./approx
    0.000000e+00

    Pronto. Você reproduziu o comportamento do OpenOffice.

    O que acontece é que o Microsoft Office não deve possuir esse tipo de wrapper, exibindo ao usuário exatamente o valor calculado pela FPU, e aconteceria dessa mesma forma se você fizesse um programa para calcular (como eu e outros aqui mostramos em C, JavaScript, Haskell e Python).

    O comportamento do OpenOffice somente é reproduzível se você utilizar os mesmos wrappers, como eu fiz no código acima.

    Agora a minha opinião – o OpenOffice deveria ter uma opção para desabilitar o uso desses wrappers caso o usuário desejar, pois isso eventualmente pode causar problemas ao importar arquivos do Microsoft Excel, ou ao comparar resultados obtidos em uma planilha com resultados obtidos usando outros programas.

    Como é difícil colar códigos aqui no WordPress do BR-Linux, colei o código que simula o comportamento do OpenOffice aqui:

    http://brlinux.pastebin.com/f4bcc56b8

    Recomendo ao Augusto, se possível, instalar o seguinte plugin:

    http://ideathinking.com/wiki/index.php/WordPress:CodeHighlighterPlugin

    André Machado (usuário não registrado) em 3/02/2009 às 2:51 pm

    Segundo fontes, o PHP também apresenta o resultado do Excel.

    Tarcísio (usuário não registrado) em 3/02/2009 às 3:02 pm

    # python
    Python 2.3.4 (#1, Jul 25 2008, 14:24:21)
    [GCC 3.4.6 20060404 (Red Hat 3.4.6-10)] on linux2
    Type “help”, “copyright”, “credits” or “license” for more information.
    >>> 1*(0.5-0.4-0.1)
    -2.7755575615628914e-17
    >>>

    Caio (usuário não registrado) em 3/02/2009 às 3:04 pm

    Faltou a resultado do Google!

    http://www.google.com.br/search?hl=pt-BR&q=1*(0%2C5-0%2C4-0%2C1)&btnG=Pesquisar&meta=

    :)

    Só para complementar, o bc retorna zero pois ele não utiliza a FPU do seu computador para fazer as contas.

    O bc utiliza aritmética de precisão arbitrária que é implementada pelo seu código em:

    http://www.google.com/codesearch/p?hl=en#CN-HQ4zhgJs/bc-1.06/lib/number.c&q=package:bc-1.06.tar.gz

    Em especial, dê uma olhada no _bc_do_sub.

    Jack Ripoff, gostaria de ver sua demonstração que 0,0999 é igual a 0,1.

    Fellype (usuário não registrado) em 3/02/2009 às 3:34 pm

    Agradeço aos usuário que mostraram que não é apenas o excel quem faz as contas “erradas”. Nunca tinha prestado atenção nisso. A coisa é mais feia do que eu pensava…

    Alan, não foi isso que ele afirmou. Ele apresentou uma dízima periódica (0,0999…) e não o 0,0999.

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 3:52 pm

    0,0999 não é igual a 0,1

    0,0999… (dizíma periódica, infinitos noves) é igual a 0,1. Demonstração:

    Seja x = 0,0999…

    Vamos multiplicar nossa igualdade por 10.

    10x = 0,999…

    Vamos subtrair x dos dois lados da nossa equação.

    10x – x = 0,999… – x

    9x = 0,999… – 0,0999…

    Mas 0,999… menos 0,0999… é igual a 0,9. Portanto

    9x = 0,9

    x = 0,9 / 9 => x = 0,1

    Q.E.D.

    Na verdade 0,0999… é simplesmente outra forma de representar o mesmo número que 0,1. Isto fica evidente se você pensar na arquimedianidade e na completude do conjunto dos números reais. Por essas propriedades não pode existir um número real imediatamente inferior a outro, pois a diferença entre os dois seria um infinitesimal e não existem infinitesimais no conjunto dos reais. Se a diferença fosse diferente de zero, é sempre possível imaginar um número entre os outros dois e cuja diferença entre eles seja menor mas ainda diferente de zero.

    O corolário disto é que todos os números racionais cuja representação decimal não é uma dízima periódica possuem uma segunda representação decimal que é uma dízima periódica (com infinitos noves), mas a demonstração disto fica para outro dia.

    Augusto e Jack, sendo dízima periódica a explicação está correta, porém, lastimavelmente, virou lugar-comum substituir a vírgula por reticências. Logo, não sabia se o Jack havia escrito a dízima ou feito a famigerada substituição.

    Abraços,

    Estou vendo que esse assunto deu bastante controvérsia.

    É algo simples, que está definido de forma clara, mas que poucas pessoas sequer fazem idéia do que acontece.

    Numeros REAIS (ponto flutuante) em computadores sempre foi um campo tortuoso. É preciso conhecer bem MATEMÁTICA e ainda melhor COMPUTAÇÃO para entender porque essas coisas acontecem.
    Temos que lembrar que os computadores realizam contas na base 2 e não na base 10. Se a conta apresentada for feita usando a base 2 haverá a geração de dizimas e necessidade de arredondamentos/truncamentos em alguma parte.

    E sendo sarcástico, alguém que precise fazer cáculos avançados onde isso faça realmente uma grande diferença deve saber matemática o suficiente para entender porque isso acontece e deveria conhecer computação o suficiente para escolher uma ferramenta de cálculo mais adequada.

    ThOR27 (usuário não registrado) em 3/02/2009 às 5:23 pm

    http://www.google.com.br/search?q=1*(0.5-0.4-0.1)

    aqui deu zero :P

    Allan Taborda (usuário não registrado) em 3/02/2009 às 6:30 pm

    Agora a minha opinião – o OpenOffice deveria ter uma opção para desabilitar o uso desses wrappers caso o usuário desejar, pois isso eventualmente pode causar problemas ao importar arquivos do Microsoft Excel, ou ao comparar resultados obtidos em uma planilha com resultados obtidos usando outros programas.

    Seria bom requisitar essa funcionalidade aos desenvolvedores do OpenOffice.org!

    “E sendo sarcástico, alguém que precise fazer cáculos avançados onde isso faça realmente uma grande diferença deve saber matemática o suficiente para entender porque isso acontece e deveria conhecer computação o suficiente para escolher uma ferramenta de cálculo mais adequada.”

    Exato. Pra isso existem softwares próprios pra cálculo científico. Ninguém vai traçar a rota pra um planeta no Excel. Trabalhar em outra base que não a binaria no computador dá diferença de performance. Mesmo wrappers você está reduzindo a performance. Como a margem de erro é mínima pros usuários comuns, a maioria dos softwares pro público geral não se importam.

    Outra demostração da igualdade é que um número é igual a outro quando a diferença entre eles for zero.
    0,1 – 0,09999… = 0,000…
    hehehehe
    Outro exemplo interessante.
    1/3 = 0,3333….
    1/3 + 1/3 + 1/3 = 0,99999…..
    Mas se você somar os “terços” dá 3/3 que é igual a 1
    Infinitesimais na matemática é muito doido!

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 7:33 pm

    Pra isso existem softwares próprios pra cálculo científico.

    Mas nós constatamos que até o Octave e o Scilab, que são programas “próprios” para computação científica, apresentam esse comportamento.

    1/3 = 0,3333….
    1/3 + 1/3 + 1/3 = 0,99999…..
    Mas se você somar os “terços” dá 3/3 que é igual a 1

    Outra demonstração interessante da igualdade usa séries infinitas. O número 0,999… pode ser escrito assim:

    0,999… = 9/10 + 9/100 + 9/1000 + …

    Mas pelo teorema da convergência das progressões geométricas com razão de módulo menor que 1, essa série converge e a soma infinita é dada pela fórmula:

    (9/10)/(1 – 1/10) = 1

    Q.E.D.

    G (usuário não registrado) em 3/02/2009 às 8:38 pm

    No google
    1 * (0.5 – 0.4 – 0.1) = 0

    Na calculadora do Gnome no normal aparece 0 .No cietifico com o padrão cientifico selecionado -1,416423594e-219

    Bruno (usuário não registrado) em 3/02/2009 às 8:46 pm

    Interessante este cálculo.
    Alguém poderia explicar como 1*(0,5-0,4-0,1) resulta -2,7755*10^-17?
    Poder ser um link até em inglês mesmo. Grato.
    Sou fã de matemática.

    Como o colega disse acima seria muito bom e o OO.o tivesse opção para desativar tais aproximações. Apesar de seguir a norma isso pode ser considerado um bug pois mesmo alterando o modo de exibição ele mostra um valor impreciso.

    G (usuário não registrado) em 3/02/2009 às 8:52 pm

    Tambem acho a matematica que eu saiba continua a mesma e o valor logico eh:
    0.5 – 0.4 = 0,1
    1*(0,1 – 0,1) = 0 Em qualquer conta

    Jack Ripoff (usuário não registrado) em 3/02/2009 às 9:15 pm

    Alguém poderia explicar como 1*(0,5-0,4-0,1) resulta -2,7755*10^-17?
    Poder ser um link até em inglês mesmo. Grato.

    http://support.microsoft.com/kb/78113

Este post é antigo (2009-02-03) e foi arquivado. O envio de novos comentários a este post já expirou.