Pregunta ¿Por qué dividir dos int no produce el valor correcto cuando se asigna al doble?


¿Cómo es eso en el siguiente fragmento?

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

c termina teniendo el valor 2, en lugar de 2.3333, como uno esperaría. Si a y b son dobles, la respuesta pasa a 2.333. Pero seguramente porque c  ya es un doble, debería haber trabajado con enteros?

Entonces, ¿cómo es que int/int=double no funciona?


73
2017-09-27 15:02


origen


Respuestas:


Esto se debe a que está utilizando la versión de división entera de operator/, que toma 2 ints y devuelve un int. Para usar el double versión, que devuelve un double, al menos uno de los ints se debe convertir explícitamente en double.

c = a/(double)b;

118
2017-09-27 15:05



Aquí está:

a) División de dos ints realiza la división de enteros siempre. Entonces el resultado de a/b en tu caso solo puede ser un int.

Si quieres mantener a y b como ints, sin embargo, divídalos por completo, debe lanzar al menos uno de ellos para duplicar: (double)a/b o a/(double)b o (double)a/(double)b.

segundo) c es un double, entonces puede aceptar un int valor en la asignación: el int se convierte automáticamente a double y asignado a c.

c) Recuerde que en la asignación, la expresión a la derecha de = se calcula primero (de acuerdo con la regla (a) anterior, y sin tener en cuenta la variable a la izquierda de =) y entonces asignado a la variable a la izquierda de = (de acuerdo con (b) arriba). Creo que esto completa la imagen.


9
2017-09-27 15:15



Con muy pocas excepciones (solo puedo pensar en una), C ++ determina la todo el significado de una expresión (o sub-expresión) de la expresión sí mismo. Lo que hagas con los resultados de la expresión no importa. En tu caso, en la expresión a / b, no hay un double en visión; todo es int. Entonces el compilador usa la división de enteros. Solo una vez que tiene el resultado, ¿considera qué hacer con él? convertirlo a double.


8
2017-09-27 15:11



Cuando divide dos enteros, el resultado será un entero, independientemente del hecho de que lo almacene en un doble.


5
2017-09-27 15:06



c es un double variable, pero el valor que se le asigna es un int valor porque es el resultado de la división de dos ints, que le da "división entera" (dejando caer el resto). Entonces, ¿qué pasa en la línea? c=a/b es

  1. a/b se evalúa, creando un tipo temporal de int
  2. el valor de lo temporal está asignado a c después de la conversión a tipo double.

El valor de a/b se determina sin referencia a su contexto (asignación a double)


4
2017-09-27 15:04



los / el operador se puede usar para división entera o división de punto flotante. Le está dando dos operandos enteros, por lo que está haciendo una división entera y luego el resultado se almacena en un doble.


3
2017-09-27 15:07



En el lenguaje C ++, el resultado de la subexpresion nunca se ve afectado por el contexto circundante (con raras excepciones). Este es uno de los principios que el lenguaje sigue cuidadosamente. La expresion c = a / b contiene una subexpresión independiente a / b, que se interpreta independientemente de cualquier cosa fuera de esa subexpresión. Al lenguaje no le importa que luego asigne el resultado a un double. a / b es una división entera. Cualquier otra cosa no importa. Verá este principio seguido en muchas esquinas de la especificación del lenguaje. Así es cómo funciona C ++ (y C).

Un ejemplo de una excepción que mencioné anteriormente es la función de asignación / inicialización del puntero en situaciones con sobrecarga de funciones

void foo(int);
void foo(double);

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

Este es un contexto donde el lado izquierdo de una asignación / inicialización afecta el comportamiento del lado derecho. (Además, la inicialización de referencia a matriz evita la disminución del tipo de matriz, que es otro ejemplo de comportamiento similar.) En todos los demás casos, el lado derecho ignora por completo el lado izquierdo.


3
2017-09-27 16:20



Esto es técnicamente un idioma dependiente, pero casi todos los idiomas tratan este tema de la misma manera. Cuando hay una discrepancia de tipo entre dos tipos de datos en una expresión, la mayoría de los idiomas intentará convertir los datos en un lado del = para unir los datos del otro lado de acuerdo con un conjunto de reglas predefinidas.

Al dividir dos números del mismo tipo (enteros, dobles, etc.) el resultado siempre será del mismo tipo (por lo que 'int / int' siempre dará como resultado int).

En este caso tienes double var = integer result que arroja el resultado entero a un doble después del cálculo en cuyo caso los datos fraccionarios ya están perdidos. (la mayoría de los idiomas harán esta conversión para evitar imprecisiones de tipo sin generar una excepción o error).

Si desea mantener el resultado como un doble, querrá crear una situación donde tenga double var = double result

La forma más fácil de hacerlo es forzar la expresión en el lado derecho de una ecuación para convertir a doble:

c = a/(double)b

La división entre un número entero y un doble dará como resultado el entero al doble (tenga en cuenta que al hacer las matemáticas, el compilador a menudo se "elevará" al tipo de datos más específico para evitar la pérdida de datos).

Después de la upcast, a terminará como un doble y ahora tienes división entre dos dobles. Esto creará la división y asignación deseada.

DE NUEVO, tenga en cuenta que esto es específico del idioma (e incluso puede ser específico del compilador), sin embargo, casi todos los idiomas (sin duda todos los que puedo pensar en la parte superior de mi cabeza) tratan este ejemplo de manera idéntica.


2
2017-09-27 15:12