Ir ao conteúdo
  • Comunicados

    • Gabriel Torres

      Seja um moderador do Clube do Hardware!   12-02-2016

      Prezados membros do Clube do Hardware, Está aberto o processo de seleção de novos moderadores para diversos setores ou áreas do Clube do Hardware. Os requisitos são:   Pelo menos 500 posts e um ano de cadastro; Boa frequência de participação; Ser respeitoso, cordial e educado com os demais membros; Ter bom nível de português; Ter razoável conhecimento da área em que pretende atuar; Saber trabalhar em equipe (com os moderadores, coordenadores e administradores).   Os interessados deverão enviar uma mensagem privada para o usuário @Equipe Clube do Hardware com o título "Candidato a moderador". A mensagem deverá conter respostas às perguntas abaixo:   Qual o seu nome completo? Qual sua data de nascimento? Qual sua formação/profissão? Já atuou como moderador em algo outro fórum, se sim, qual? De forma sucinta, explique o porquê de querer ser moderador do fórum e conte-nos um pouco sobre você.   OBS: Não se trata de função remunerada. Todos que fazem parte do staff são voluntários.
    • DiF

      Poste seus códigos corretamente!   21-05-2016

      Prezados membros do Fórum do Clube do Hardware, O Fórum oferece um recurso chamado CODE, onde o ícone no painel do editor é  <>     O uso deste recurso é  imprescindível para uma melhor leitura, manter a organização, diferenciar de texto comum e principalmente evitar que os compiladores e IDEs acusem erro ao colar um código copiado daqui. Portanto convido-lhes para ler as instruções de como usar este recurso CODE neste tópico:  
Pedrohtico

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

Recommended Posts

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.

Editado por Pedrohtico
  • Curtir 1

Compartilhar este post


Link para o post
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]);

 

Editado por vangodp
  • Curtir 2

Compartilhar este post


Link para o post
Compartilhar em outros sites

Deu certo dessa forma. 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?

  • Curtir 1

Compartilhar este post


Link para o post
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

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acabei de fazer um programa igual ao seu. Tentei já inicializando o vetor de inteiros com 10 e 30 e depois tentei pedindo o valor ao usuário. Em ambos os casos o resultado foi 11 e 35, e eu não faço ideia o porquê haha.

  • Curtir 1

Compartilhar este post


Link para o post
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

Compartilhar este post


Link para o post
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.

Editado por vangodp
  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Isrnick, muito bom. Eu acho que eu nunca imaginaria isso como o problema, então obrigado haha.

 

E vangodp, valeu também pela explicação, agora entendi melhor.

 

Obrigado pelos dois pela ajuda :)

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário






Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações 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

×