Por que dividir dois int não produz o valor correto quando atribuído ao dobro?

Por que isso no seguinte trecho

int a = 7; int b = 3; double c = 0; c = a / b; 

c acaba tendo o valor 2, em vez de 2.3333, como seria de se esperar. Se a e b são duplos, a resposta é de 2.333. Mas certamente porque c já é um duplo, deveria ter trabalhado com inteiros?

Então, como é que int/int=double não funciona?

Isso ocorre porque você está usando a versão de divisão inteira do operator/ , que leva 2 int retorna um int . Para usar a versão double , que retorna um double , pelo menos um dos int deve ser explicitamente convertido em double .

 c = a/(double)b; 

Aqui está:

a) Dividindo dois int s realiza uma divisão inteira sempre. Então o resultado de a/b no seu caso só pode ser um int .

Se você quiser manter a e b como int s, e ainda dividi-los completamente, você deve converter pelo menos um deles para double: (double)a/b ou a/(double)b ou (double)a/(double)b .

b) c é um double , por isso pode aceitar um valor int na atribuição: o int é automaticamente convertido em double e atribuído a c .

c) Lembre-se que na atribuição, a expressão à direita de = é calculada primeiro (de acordo com a regra (a) acima e sem considerar a variável à esquerda de = ) e então atribuída à variável à esquerda de = ( de acordo com (b) acima). Eu acredito que isso conclui a imagem.

Com pouquíssimas exceções (só consigo pensar em uma), o C ++ determina o significado completo de uma expressão (ou subexpressão) da própria expressão. O que você faz com os resultados da expressão não importa. No seu caso, na expressão a / b , não há um double à vista; tudo é int . Então o compilador usa a divisão inteira. Apenas uma vez que tenha o resultado, considere o que fazer com ele e converta-o para o double .

Quando você divide dois inteiros, o resultado será um inteiro, independentemente do fato de você armazená-lo em um duplo.

c é uma variável double , mas o valor que está sendo atribuído a ela é um valor int porque resulta da divisão de dois int s, o que lhe dá “divisão inteira” (perdendo o restante). Então, o que acontece na linha c=a/b é

  1. a/b é avaliado, criando um temporário do tipo int
  2. o valor do temporário é atribuído a c após a conversão para o tipo double .

O valor de a/b é determinado sem referência ao contexto (atribuição para double ).

O operador / pode ser usado para divisão inteira ou divisão de ponto flutuante. Você está dando a ele dois operandos inteiros, então está fazendo uma divisão inteira e então o resultado está sendo armazenado em um duplo.

Na linguagem C ++, o resultado da subexposição nunca é afetado pelo contexto circundante (com algumas raras exceções). Este é um dos princípios que a linguagem segue cuidadosamente. A expressão c = a / b contém uma subexpressão independente a / b , que é interpretada independentemente de qualquer coisa fora dessa subexpressão. A linguagem não se importa que mais tarde você irá atribuir o resultado a um double . a / b é uma divisão inteira. Qualquer outra coisa não importa. Você verá este princípio seguido em muitos cantos da especificação da linguagem. Isso é como o C ++ (e C) funciona.

Um exemplo de uma exceção que mencionei acima é a atribuição / boot do ponteiro de function em situações com sobrecarga de function

 void foo(int); void foo(double); void (*p)(double) = &foo; // automatically selects `foo(fouble)` 

Este é um contexto em que o lado esquerdo de uma atribuição / boot afeta o comportamento do lado direito. (Além disso, a boot de referência para matriz impede o decaimento do tipo de matriz, que é outro exemplo de comportamento semelhante). Em todos os outros casos, o lado direito ignora completamente o lado esquerdo.

Isso é tecnicamente um idioma dependente, mas quase todas as linguagens tratam esse assunto da mesma forma. Quando há uma incompatibilidade de tipos entre dois tipos de dados em uma expressão, a maioria dos idiomas tentará converter os dados em um lado do = para corresponder aos dados no outro lado, de acordo com um conjunto de regras predefinidas.

Ao dividir dois números do mesmo tipo (inteiros, duplos, etc.), o resultado será sempre do mesmo tipo (então ‘int / int’ sempre resultará em int).

Neste caso, você tem o resultado double var = integer result qual lança o resultado inteiro para um double após o cálculo , caso em que os dados fracionários já estão perdidos. (a maioria dos idiomas fará essa conversão para evitar imprecisões de tipo sem gerar uma exceção ou erro).

Se você quiser manter o resultado como um double, você vai querer criar uma situação em que você tenha double var = double result

A maneira mais fácil de fazer isso é forçar a expressão no lado direito de uma equação para converter em double:

c = a/(double)b

A divisão entre um inteiro e um duplo resultará em converter o inteiro para o dobro (observe que, ao fazer matemática, o compilador geralmente “atualiza” para o tipo de dados mais específico que é para evitar a perda de dados).

Após o upcast, a vai acabar como um duplo e agora você tem divisão entre dois duplos. Isso criará a divisão e atribuição desejadas.

NOVAMENTE, observe que isso é específico da linguagem (e pode até mesmo ser específico do compilador), no entanto quase todas as linguagens (certamente todas as que posso pensar em cima da minha cabeça) tratam este exemplo de forma idêntica.