Quanto seria (200*0,7) + 200? 340 você diria? Então você deve ler este artigo. Dependendo da situação esta operação matemática não resultará em 340. Absurdo? Quem programa em linguagem de programação C deve ficar atento!
int main()
{
int a;
a = 200;
a = (a * 0.7) + a;
printf("O valor de a eh %d\n", a);
}
Agora dá para entender. Ao realizar 0.7 * 200, na verdade foi feito, lá nos bastidores "bitianos" a operação 0.69999999999999995559 * 200 e isto resulta em 139.99999999999999111800.
Ao somar com 200, o valor final é 339.99999999999999111800! Mesmo que isto seja praticamente 340, como está sendo atribuído ao a que é um inteiro, as casas decimais são sumariamente perdidas e o número fica 339!!!
Isto não ocorreria se variável a fosse do tipo double, pois neste caso o C realiza arredondamentos. Isto também não ocorre no PHP pelo mesmo motivo. Ocorre em C porque ele converte double para int removendo as casas decimais, por mais doloroso que isto seja!
Deve-se registrar aqui que tal "bug" não ocorre em compiladores gcc de 64 bits.
[2] Comentário enviado por jmsandy em 20/03/2008 - 17:16h
Opa, blza?
Este episódio não acontece somente com este produto. Pegando o seu exemplo 200 x 0.7, o fator 0.7, quase todos os seus múltiplos o valor é arredondado para 1 a menos.
Achei bastante interessante e testei aqui no trabalho em um compilador for Windows quando chegar em casa vou testar no Linux para tirar a tema. Mais observação muito interessante. Em determinados compiladores, como o dá Borland, existe um erro quanto a ponto flutuante que voce tem que declarar um prototipo de uma função para ele não acontecer. E támbém o flush(stdin) para limpar o buffer(ou alguma coisa parecida é que não me recordo muito bem).
Está de parabéns pela observação.
[3] Comentário enviado por antonioclj em 20/03/2008 - 17:47h
Mas isto vai acontecer mesmo. Você declarou um inteiro e faz uma multiplicação com ponto flutuante, vai dar inteiro na resposta. Você tem que usar o modificador float e não int. Bom isto é para os porgramadores de plantão.
[4] Comentário enviado por elgio em 20/03/2008 - 17:51h
Oi Antonio.
Sabemos disto.
Mas acho que tu não entendeu direito o FOCO que eu explorei.
No caso a multiplicacao 0.7*200 devia resultar em um inteiro redondo, assim como 0.6 * 100 que resulta em 60.
Não tem poblema algum misturar int com doubles ou float em C, desde que VOCÊ SAIBA o que está fazendo. Eu uso muito isto (mesmo que raramente saiba o que estou fazendo :-D)
[10] Comentário enviado por elgio em 21/03/2008 - 11:44h
Gabriel!.
Em arquiteturas 64 bits este erro não ocorre.
Não sei exatamente PORQUE NÃO OCORRE, pois testei em um servidor 64 bits que tenho acesso e vi que os arredondamentos SÃO FEITOS!!
Inclusive COM MESMA versão de GCC.
Meu notebook, 32 bits, GCC 4.1.2.
Tamanho de um double: 8 bytes
0.7 = 0.6999999999999999555910790149937383830547
Em um servidor 64 bits, GCC 4.1.2
Tamanho de um double: 8 bytes
0.7 = 0.6999999999999999555910790149937383830547
Mas no 64 bits o GCC informa CORRETAMENTE 340 como tu falou!
Se alguém sabe o motivo, poderia contribuir. Este GCC para 64 bits é o PRIMEIRO COMPILADOR C que faz o cálculo CORRETO! O Dev++, Borland e GCC 32 bits fazem errado.
[11] Comentário enviado por elgio em 21/03/2008 - 11:45h
pedroarthur.jedi: sim, eu conheço bem os erros de representação.
Tanto que no artigo eu descrevo isto como um erro.
O que ocorreu neste caso NÃO É UM MISTÉRIO. Só escrevi o artigo para que todos que programem em C tenham muito cuidado com estes erros.
[13] Comentário enviado por rui_alex em 21/03/2008 - 18:22h
[There was strong agreement in the C89 Committee that floating values should truncate toward zero when converted to an integer type, the specification adopted in the Standard.]
[Many results are exact or correctly rounded when computed with twice the number of digits of
precision as the data.]
-c99 Rationale-
Na arquitectura 64 bits suponho que os floats sejam pelo menos 8 bytes?
[14] Comentário enviado por elgio em 21/03/2008 - 20:30h
Bom...
O que eu descobri com um sizeof foi:
32 bits: int, long int e float em 32 bits. double em 64 bits, "long double" com 12 bytes (96 bits). Mas isto o que o gcc retorna, não quer dizer que seja o que a ULA e o co-processador suporta (alguém bom em Hardware ai?)
No 64 bits, MESMA VERSÃO de gcc, obtive: int e float em 32 bits, double em 64 bits e "long double" com 16 bytes (128 bits).
Mas é estranho, pois em ambas o problema de PRECISÃO EXISTE, isto é, 0.7 não é representável com PRECISÃO.
Por que diabos o gcc para 64 bits realiza algum ARREDONDAMENTO?
[16] Comentário enviado por luizpetiz em 22/03/2008 - 14:45h
É... legalzinho!
Psiu! Tô falando assim porque o cara é meu professor na ulbra. Não posso dizer que é um baita artigo e só um cara como ele poderia dedicar-se a esses assuntos e tal.., que ele é fera mesmo, se não ele se convence...
[18] Comentário enviado por estevao90 em 22/03/2008 - 21:01h
mt bom...
meu professor sempre alerta a gente quando a esse mistério do C
o negócio é: se for precisar de ponto flutuante, coloca todas variáveis envolvidas como float, por exemplo, facilita a vida! rsrs
[21] Comentário enviado por anonimo1234 em 29/03/2008 - 23:44h
Interessante,um bom exemplo da importancia da definição de tipos,pois o tipo apropriado para essa operação creio que seja float e não int,para não ficarmos sujeitos a arrendodamentos imperfeitos do C.
[22] Comentário enviado por SamL em 04/12/2008 - 23:21h
Eu executei o script e ocorreu o mesmo erro, 'a=339'
Mas consegui evitar isso fazendo assim:
#include <stdio.h>
int main()
{
int a;
a = 200;
a = (a *7)/10 + a;//ou a = (a*7/10) + a; ao inves de '(a*0.7)'
printf("O valor de a eh %d\n", a);
return 0;
}
e obtive o resultado correto:
'O valor de a eh 340'
#include <math.h>
#define ARRED(x) floor( x + 0.5 ) //Isso retorna um inteiro
#define ARRED2(x, z) floor( x*pow(10, z) + 0.5 )/pow(10, z) //sendo z o numero de casas decimais
Assim que for possível vou testar em casa no linux.