Ir ao conteúdo
  • Cadastre-se

Problema com multiplicação de variáveis em C


Pedrohtico

Posts recomendados

Dentro de um programa que eu fiz, tem um detalhe que está me incomodando. Existe um vetor de inteiros que em determinado momento eu preciso multiplicar um de seus valores por 1.2. Quando eu faço isso dessa forma, quando o valor do vetor é 10, por exemplo:

ataque1[i] = 1.2*ataque1[i];

O resultado sempre sai 1 abaixo do esperado. No caso, a multiplicação de 1.2*10 dá 11 como resultado. Quando eu faço com 30, dá 35 ao invés de 36, etc.

Quando eu faço da seguinte forma:

ataque1[i] = 12*ataque1[i]/10;

O resultado dá certo. 12, quando ataque1 é 10, por exemplo.

Eu imagino que seja algum problema por estar multiplicando um float (1.2) por uma variável do tipo inteiro. Se alguém puder me ajudar, eu agradeceria.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

você esta multiplicando valores entre varios tipos diferentes de dados, e esta acontecendo conversões implícitas dedados. procure demonstrar com claridade de que se trata cada tipo de dado tipo: printf("%d", (int)((double)1.2 * (int)10)  );

adicionado 8 minutos depois
ataque1[i] = 1.2*ataque1[i];

 por exemplo é como se fosse
 

int = double*int

. Talvez seja o que você busca:
 

ataque1[i] = (int)( (float)1.2*(int)ataque1[i]);

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Não consegui reproduzir seus resultados...

 

Testei com esse código:

#include <stdio.h>

int main()
{
    int a[2] = {10, 30};
    a[0] = 1.2 * a[0];
    a[1] = 1.2 * a[1];
    printf("%d %d\n", a[0], a[1]);

    return 0;
}

E os resultados foram:

12 36

 

Talvez seja diferença de compilador? Fazendo esse teste no seu ocorre o mesmo problema?

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Testei o mesmo código em outro compilador e deu 11 e 35.

 

E descobri porque acontece...

 

O problema é que 1.2 dá dízima periódica na forma binária, ficando:

(1.2)10 = (1.00110011001100110011...)2

 

Então surge um problema de arredondamento... Veja, convertendo o número binário com 20 casas após a vírgula para decimal resulta em:

 

(1.00110011001100110011)2   =>>>   (1.19999980926513671875)10

 

Se multiplicar isto por 10 obterá:

 

11.9999980926513671875

 

E separando apenas a parte inteira desse número você obtém 11, ao invés de 12 como esperado.

 

 

Então o arredondamento muda dependendo em que posição da dízima você para...

 

Nesse caso a multiplicação com 1.2 como double (que é como a constante é interpretada quando nenhum tipo é especificado) acaba arredondando para baixo.

 

Ou seja, contrariamente ao esperado nesse caso a maior precisão do double resulta em um resultado errado, enquanto com float é arrendado para cima resultando no valor correto. Mas observe que isso poderia mudar se fosse outro número racional com dízima na forma binária, pois em outro caso o double poderia ser arredondado corretamente e o float de modo errado dependendo em que posição do número na forma binária o valor para de ser armazenado nesses tipos de variáveis...

 

Como garantir que isso não aconteça? Você pode fazer contas apenas com números inteiros, como você fez, ou então usar uma função para sempre obter o valor do teto do número de ponto flutuante (ceil() da biblioteca math.h) antes de armazenar na variável inteira.

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

2 horas atrás, Pedrohtico disse:

Mas não entendi muito bem o porquê. Quando não se especifica os tipos, o compilador meio que modifica um pouco os valores para realizar operações de tipos diferentes?

Simplesmente você "imagina" o que não é. Para você entender...
Na seguinte declaração com atribuição você será capaz de me dizer o que está acontecendo?:
float f = 1.2;

Se sua resposta é que estou tentando atribuir um double a um float, você acertou, caso contrario você precisa estudar mais... muito mais. >_<

Igualmente a seguinte atribuição...
O que acontece se eu fizer:
int n = 1.2;

Se sua resposta é que eu to tentando atribuir um double a um int você acertou, porém em parte. Na realidade n simplesmente tomou o valor 1 perdendo a parte fracionaria, pois um int jamais poderá guardar 1.2, acontece uma conversão implícita de tipos de double a int com perda de dados de por meio. É a mesma coisa que acontece quando você tenta multiplicar um double por um int (1.2*ataque1). Ao tentar multiplicar um double por um int você perde a parte fracionaria, e por isso geram resultados incorretos. Total... falha de lógica devido a um mal domínio da linguagem.

Sempre quando for realizar uma operação entre diferentes tipos de dados, certifique-se que não há perdas de dados por realizar operações entre tipos diferentes, por isso lhe aconselhei que usa-se cast explicito.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...