sexta-feira, setembro 28, 2007

Será que o Excel 2007 Desaprendeu a Aritmética?

Esta semana foi descoberto um problema vexatório no Excel 2007, que apresenta um resultado completamente errado para uma conta simples. Esta descoberta tem gerado manchetes do tipo "Excel 2007 não sabe multiplicar", mas o que realmente se passa?

O Bug

O exemplo mais comum do problema consiste em entrar em um célula com a expressão "=77,1*850" (quem estiver com o Windows configurado para o padrão americano deve entrar com '.' no lugar da ','). O resultado apresentado é 100.000 ao invés do valor correto 65.535.

Como Isto Ocorre?

Da mesma forma que a maioria das planilhas e aplicativos que manipulam números, o Excel trabalha internamente com os números em um formato padronizado, o IEEE 754. Este formato é o mais comumente usado e é suportado diretamente pelos processadores atualmente em uso nos PCs.

Este formato é do tipo ponto flutuante, no qual o número é armazenado em duas partes: a mantissa (que é o número em si) e o expoente (que indica onde está a separação entre a parte inteira e fracionária). Uma das vantagens deste formato é suportar uma faixa grande de números em uma capacidade baixa de armazenamento. Por exemplo, vamos supor que vamos armazenar números decimais em três dígitos. Se usarmos um ponto fixo após o primeiro dígito, podemos trabalhar com números entre 0,00 e 9,99. Se considerarmos os dois primeiros dígitos são a mantissa e o terceiro é o expoente, podemos trabalhar com números entre 0,00 e 990.000.000. Uma desvantagem óbvia é que quando somamos números muito diferentes perdemos precisão.

Um outro ponto importante é que neste tipo de notação podemos armazenar somente um subconjunto dos números reais. No meu exemplo podemos armazenar 0,01 e 0,02 mas nenhum dos infinitos números entre eles.

Para complicar o entendimento, na notação IEEE 754 trabalhamos com potências de 2 e portanto temos um 'ponto binário' ao invés de 'ponto decimal'. Como consequência números 'triviais' na notação decimal não podem ser representados na notação binária e vice versa.

O que tem isto a ver com o bug? A primeira coisa é que 77,1 não possui representação exata no formato IEEE 754. Ao multiplicar este valor por 850 obtemos um valor que não é exatamente igual a 65.535 (mas extremamente próximo).

Ao contrário do indicado pelas manchetes, o Excel faz a conta direitinho (quem faz a conta é a CPU não o Excel). Aonde ele 'se borra' é na hora de apresentar o resultado na tela. Ou seja, ao converter a representação binária do resultado para caracteres.

É Grave?

Segundo a Microsoft, o erro na apresentação ocorre somente para 12 combinações das quase 10^19 possíveis. É claro que as operações que levam a estas combinações são também quase infinitas e independem dos números e operações envolvidos. Considerando o tempo que o Excel está no mercado, dá para ver como os casos reais são raros.

Como o erro está na apresentação e não no cálculo, se o valor for usado em outros cálculos o resultado final provavelmente vai ser apresentado corretamente. Quando a Microsoft liberar uma correção, bastará carregar a planilha para o resultado correto ser apresentado, não existe nada a corrigir na planilha em si.

Portanto o problema é mais grave para a imagem da Microsoft que para os seus clientes.

Mas Como Saiu Com Este Bug?

A pergunta chave é: como testar para pegar um bug destes?

Uma vez que o erro está na apresentação, testes automatizados que verifiquem o resultado em si e não o valor apresentado na tela não vão pegar o erro.

O lugar mais provável seria no teste unitário da rotina que converte o número da representação interna para o string apresentado. Considerando a quantidade quase infinita de casos a testar e o minúsculo número de casos problemáticos, fica fácil perceber que é difícil um teste não dirigido pegar este problema. As informações disponíveis são insuficientes para saber se o problema acontece em algum caso limite, por exemplo onde o algorítimo precisa escolher entre dois caminhos ou onde alguma variável pode sofrer overflow ou underflow. Em caso afirmativo, provavelmente faltou um caso de teste que verificasse o funcionamente correto nos dois lados do limite.

Referências

Fiquei sabendo do problema no Joel On Software. Joel que, não por acaso, foi gerente de projeto do Excel (no milênio passado).

A descrição do problema pelos projetistas do Excel pode ser vista aqui.

Um comentário:

Luciano disse...
Este comentário foi removido pelo autor.