quinta-feira, 8 de fevereiro de 2007

Erro conhecido

float i = 0.00F;
while(i<1)
{
i+=0.01F;
}
Console.WriteLine(i);

Qual o valor de i que era suposto mostrar na consola?
hmmm...
hmmmmmmmm...
hmmmmmmmmmmmmmm....
Se disseste 1,teóricamente estás certo! Na prática (executando) o valor é 1,009999

Isto deve-se a problemas já muito antigos com os arredondamentos de float.Deve-se ao hardware e a norma que foi seguida para a construção do mesmo. Podem ver mais detalhes neste site:
Floating Point

Aqui ficam mais 2 exemplos cujos resultados deixam a desejar
float y = (float) (1 - (0.3 + 0.6 + 0.1));
Console.WriteLine(y);
resultado: y=1,110223E-16

double z = 1 - (0.3 + 0.6 + 0.1);
Console.WriteLine(z);
resultado: z=1,11022302462516E-16

13 comentários:

Bruno Silva disse...

é só 1 cadito estupido, por acaso não sabia isso, nunca me tinha deparado com uma situação dessas com floats :D eheh! tá giro, mas isso é o bug de alguem certamente :P

Unknown disse...

Pah não sei é como não foi resolvido ainda...

Sendo um problema de hardware, é independente da linguagem... aposto que os EUA estão a perder a guerra do iraque por causa destes cálculos mal feitos :p

Unknown disse...

Obviamente isso nunca vai desaparecer, mas o erro dos 2 exemplos debaixo parece-me aceitável.
Deverá ser de hardware. O primeiro é k n... Em que compilador acontece isso?

Unknown disse...

compilador do c#

Unknown disse...

Ambos são erros de hardware sergio!

Já testei isso tanto em compilador Java como .NET.

Em relação ao "Obviamento isso nunca vai desaparecer", não sei porque dizes isso

Unknown disse...

Porque, por melhor que seja o hardware, terá sempre um erro no cálculo de fracções. Há sempre um limite que consegue atingir. Não pode dar-te um resultado correcto quando existem infinitas casas decimais.

Claro que com o primeiro erro, é mais crasso, mas estou a defender, obviamente os outros com +/- 1E-16.

Supostamente deveria ser capaz de te explicar o porquê do primeiro erro, já que dei isso nas teóricas de uma cadeira do 4º ano. Eu estive nessa aula, mas tava com tanta vontade de ligar ao que o prof disse como ele (soneca) de falar a velocidade de gente.

Qt à guerra do iraque, por acaso já houve pessoas a morrer em explosões de foguetões na NASA por causa do uso de 1 float em vez de double no cálculo de algo relacionado com o combustivel.

Unknown disse...

Ya, quando falei na guerra do iraque não foi totalmente a toa!
Houve uma guerra em que os EUA não foram capaz de interceptar um missil com os seus SAMs devido a questões de aproximações. A máquina simplesmente foi aumentando o erro até o erro ter sido tão grande ao ponto de falhar o missil...

Em relação aos limites do hardware, é óbvio que o hardware tem limites nos seus cálculos a nivel de casas decimais, no entanto este não era suposto ser o caso...

O que falas é em cálculos com muitas casas decimais onde se torna razoável o hardware falhar por atingir um limite

António Vaz disse...


The standard behavior of computer hardware is to round the ideal (infinitely precise) result of an arithmetic operation to the nearest representable value, and give that representation as the result. In practice, there are other options. IEEE-754-compliant hardware allows one to set the rounding mode to any of the following:

* round to nearest (the default; by far the most common mode)
* round up (toward +∞; negative results round toward zero)
* round down (toward −∞; negative results round away from zero)
* round toward zero (sometimes called "chop" mode; it is similar to the common behavior of float-to-integer conversions, which convert −3.9 to −3)

In the default rounding mode the IEEE 754 standard mandates the round-to-nearest behavior described above for all fundamental algebraic operations, including square root. ("Library" functions such as cosine and log are not mandated.) This means that IEEE-compliant hardware's behavior is completely determined in all 32 or 64 bits.

The mandated behavior for dealing with overflow and underflow is that the appropriate result is computed, taking the rounding mode into consideration, as though the exponent range were infinitely large. If that resulting exponent can't be packed into its field correctly, the overflow/underflow action described above is taken.

The arithmetical distance between two consecutive representable floating point numbers is called an "ULP", for Unit in the Last Place. For example, the numbers represented by 45670123 and 45670124 hexadecimal is one ULP. An ULP is about 10−7 in single precision, and 10−16 in double precision. The mandated behavior of IEEE-compliant hardware is that the result be within one-half of an ULP.


Ai e tal eu plagiei a wikipédia na busca da razão do dito erro e voilá, merda da grossa ao definir standards .... cheira-me a m$

Unknown disse...

por acaso falta saber se o mm acontece com outros SO...

Unknown disse...

Sinceramente sergio ainda não percebi porque dizes essas coisas...
Se são problemas de hardware, os cálculos serão feitos de forma igualmente errada independentemente do SO que estejamos a falar...
Explica-te...

Unknown disse...

Onde viste que o primeiro erro é de hardware?

Unknown disse...

Ambos são cálculos relacionados com o uso de floats

Nenhum dos exemplos vi que era de hardware, mas o site que apresentei referia que existem esses problemas a nivel de floats dependendo das normas de hardware que estejam a ser utilizadas...

Já agora, porque é que um te parece problema de hardware e o outro não?

Unknown disse...

Por causa da casa decimal onde acontece.
Os últimos sao limitações do hardware.
O primeiro só pode ser bug. Resta saber se será mm de hardware ou de como o SO o utiliza...