Reglas de conversión de tipo implícito en operadores de C ++

Quiero ser mejor acerca de saber cuándo debería lanzar. ¿Cuáles son las reglas de conversión de tipo implícito en C ++ al agregar, multiplicar, etc. Por ejemplo,

int + float = ? int * float = ? float * int = ? int / float = ? float / int = ? int / int = ? int ^ float = ? 

etcétera…

¿Siempre se evaluará la expresión como el tipo más preciso? ¿Las reglas son diferentes para Java? Por favor corrígeme si he formulado esta pregunta de manera incorrecta.

En los operadores de C ++ (para los tipos de POD) siempre actúan sobre objetos del mismo tipo.
Por lo tanto, si no son lo mismo, se promoverá para que coincida con el otro.
El tipo de resultado de la operación es el mismo que operandos (después de la conversión).

 If either is long double the other is promoted to long double If either is double the other is promoted to double If either is float the other is promoted to float If either is long long unsigned int the other is promoted to long long unsigned int If either is long long int the other is promoted to long long int If either is long unsigned int the other is promoted to long unsigned int If either is long int the other is promoted to long int If either is unsigned int the other is promoted to unsigned int If either is int the other is promoted to int Both operands are promoted to int 

Nota. El tamaño mínimo de las operaciones es int . Entonces short / char se promueve a int antes de que la operación finalice.

En todas sus expresiones, el int se promueve a un valor float antes de que se realice la operación. El resultado de la operación es un float .

 int + float => float + float = float int * float => float * float = float float * int => float * float = float int / float => float / float = float float / int => float / float = float int / int = int int ^ float =>  

Las operaciones aritméticas que implican float dan como resultado float .

 int + float = float int * float = float float * int = float int / float = float float / int = float int / int = int 

Para más detalles, responde. Mira lo que dice la sección §5 / 9 del Estándar C ++

Muchos operadores binarios que esperan operandos de tipo aritmético o de enumeración causan conversiones y producen tipos de resultados de forma similar. El propósito es producir un tipo común, que también es el tipo del resultado .

Este patrón se denomina conversiones aritméticas habituales, que se definen de la siguiente manera:

– Si cualquiera de los dos operandos es del tipo double long, el otro se convertirá a double double.

– De lo contrario, si cualquiera de los dos operandos es doble, el otro se convertirá en doble.

– De lo contrario, si cualquiera de los operandos es flotante, el otro se convertirá en flotante.

– De lo contrario, las promociones integrales (4.5) se realizarán en ambos operandos.54)

– Entonces, si cualquiera de los operandos tiene un largo sin signo, el otro se convertirá a largo sin signo.

– De lo contrario, si un operando es un int largo y el otro unsigned int, entonces si un int largo puede representar todos los valores de un int sin signo, el int sin signo se convertirá en un int largo; de lo contrario, ambos operandos se convertirán a unsigned long int.

– De lo contrario, si el operando es largo, el otro se convertirá en largo.

– De lo contrario, si ninguno de los operandos está sin firmar, el otro se convertirá en unsigned.

[Nota: de lo contrario, el único caso restante es que ambos operandos son int]

Dado que las otras respuestas no hablan sobre las reglas en C ++ 11 aquí hay una. Del estándar C ++ 11 (borrador n3337) §5 / 9:

Este patrón se denomina conversiones aritméticas habituales , que se definen de la siguiente manera:

– Si cualquiera de los dos operandos tiene un tipo de enumeración con ámbito, no se realizan conversiones; si el otro operando no tiene el mismo tipo, la expresión está mal formada.

– Si cualquiera de los dos operandos es del tipo double long, el otro se convertirá a double double.

– De lo contrario, si cualquiera de los dos operandos es doble, el otro se convertirá en doble.

– De lo contrario, si cualquiera de los operandos es flotante, el otro se convertirá en flotante.

– De lo contrario, las promociones integrales se realizarán en ambos operandos. A continuación, se aplicarán las siguientes reglas a los operandos promocionados:

– Si ambos operandos tienen el mismo tipo, no se necesita conversión adicional.

– De lo contrario, si ambos operandos tienen tipos enteros con signo o ambos tienen tipos enteros sin signo, el operando con el tipo de rango de conversión entero menor se convertirá al tipo del operando con mayor rango.

– De lo contrario, si el operando que tiene un tipo entero sin signo tiene un rango mayor o igual que el rango del tipo del otro operando, el operando con tipo entero con signo se convertirá al tipo del operando con tipo entero sin signo.

– De lo contrario, si el tipo del operando con tipo entero con signo puede representar todos los valores del tipo del operando con tipo entero sin signo, el operando con tipo entero sin signo se convertirá al tipo del operando con tipo entero con signo.

– De lo contrario, ambos operandos se convertirán al tipo de entero sin signo correspondiente al tipo del operando con tipo entero con signo.

Vea aquí una lista que se actualiza con frecuencia.

Esta respuesta se dirige en gran parte a un comentario hecho por @ RafałDowgird:

“El tamaño mínimo de las operaciones es int.” – Esto sería muy extraño (¿qué pasa con las architectures que soportan eficazmente las operaciones de char / short?) ¿Esto realmente está en la especificación de C ++?

Tenga en cuenta que el estándar C ++ tiene la importantísima regla “como si”. Ver la sección 1.8: Ejecución del progtwig:

3) Esta disposición a veces se denomina regla “como si”, porque una implementación es libre de ignorar cualquier requisito del Estándar, siempre que el resultado sea como si se hubiera obedecido el requisito, en la medida en que pueda determinarse a partir de lo observable. comportamiento del progtwig.

El comstackdor no puede configurar un int para que sea de 8 bits, incluso si fuera el más rápido, ya que el estándar exige un int mínimo de 16 bits.

Por lo tanto, en el caso de una computadora teórica con operaciones súper rápidas de 8 bits, la promoción implícita a int para la aritmética podría ser importante. Sin embargo, para muchas operaciones, no se puede decir si el comstackdor realizó realmente las operaciones en la precisión de un int y luego se convirtió en un char para almacenar en su variable, o si las operaciones se realizaron en char todo el tiempo.

Por ejemplo, considere unsigned char = unsigned char + unsigned char + unsigned char , donde la sum se desbordará (supongamos un valor de 200 para cada uno). Si promocionaras a int , obtendrías 600, que luego se convertirían implícitamente en un unsigned char , que incluiría el módulo 256, dando así un resultado final de 88. Si no hicieras tales promociones, tendrías que envolverlas entre las dos primeras adiciones, lo que reduciría el problema de 200 + 200 + 200 a 144 + 200 , que es 344, que se reduce a 88. En otras palabras, el progtwig no conoce la diferencia, por lo que el comstackdor es libre de ignorar el mandato de realizar operaciones intermedias en int si los operandos tienen una clasificación inferior a int .

Esto es cierto en general de sum, resta y multiplicación. No es cierto en general para división o módulo.

Si excluye los tipos sin firmar, hay una jerarquía ordenada: char firmado, corto, int, largo, largo largo, flotante, doble, largo doble. Primero, cualquier cosa que venga antes de int en lo anterior se convertirá a int. Luego, en una operación binaria, el tipo de menor clasificación se convertirá en el más alto, y los resultados serán del tipo de mayor. (Observará que, desde la jerarquía, cada vez que se trata de un punto flotante y un tipo integral, el tipo integral se convertirá al tipo de coma flotante).

Unsigned complica las cosas un poco: perturba el ranking, y partes del ranking se convierten en implementaciones definidas. Debido a esto, es mejor no mezclar firmado y sin signo en la misma expresión. (La mayoría de los expertos en C ++ parecen evitar unsigned a menos que se trate de operaciones bit a bit. Eso es, al menos, lo que recomienda Stroustrup).

Mi solución al problema obtuvo WA (respuesta incorrecta), luego cambié uno de int a long long int y le di AC (accept) . Previamente, estaba tratando de hacer long long int += int * int , y luego de rectificarlo a long long int += long long int * int . Googleando, se me ocurrió,

1. Conversiones aritméticas

Condiciones para la conversión de tipo:

Condiciones cumplidas —> Conversión

  • Cualquiera de los dos operandos es de tipo double long . —> Otro operando se convierte en tipo double long .

  • La condición previa no se cumple y ninguno de los dos operandos es de tipo doble . —> Otro operando se convierte a tipo double .

  • Las condiciones anteriores no se cumplen y ninguno de los operandos es de tipo flotante . —> Otro operando se convierte en tipo float .

  • No se cumplen las condiciones anteriores (ninguno de los operandos es de tipo flotante). —> Las promociones integrales se realizan en los operandos de la siguiente manera:

    • Si cualquiera de los operandos es de tipo unsigned long , el otro operando se convierte en tipo unsigned long .
    • Si la condición anterior no se cumple, y si el operando es de tipo largo y el otro de tipo unsigned int , ambos operandos se convierten a tipo unsigned long .
    • Si las dos condiciones anteriores no se cumplen, y si cualquiera de los dos operandos es de tipo largo , el otro operando se convierte en tipo largo .
    • Si las tres condiciones anteriores no se cumplen, y si cualquiera de los dos operandos es de tipo unsigned int , el otro operando se convierte en unsigned int .
    • Si no se cumple ninguna de las condiciones anteriores, ambos operandos se convierten a tipo int .

2. Reglas de conversión de enteros

  • Promociones enteras:

Los tipos enteros más pequeños que int se promueven cuando se realiza una operación en ellos. Si todos los valores del tipo original se pueden representar como un int, el valor del tipo más pequeño se convierte en un int; de lo contrario, se convierte a unsigned int. Las promociones enteras se aplican como parte de las conversiones aritméticas habituales a ciertas expresiones de argumento; operandos de los operadores unarios +, – y ~; y operandos de los operadores de turno.

  • Rango de conversión de enteros:

    • No hay dos tipos enteros con signo que tengan el mismo rango, incluso si tienen la misma representación.
    • El rango de un tipo de entero con signo debe ser mayor que el rango de cualquier tipo de entero con signo con menos precisión.
    • El rango de long long int será mayor que el rango de long int , que será mayor que el rango de int , que será mayor que el rango de short int , que será mayor que el rango de signed char .
    • El rango de cualquier tipo de entero sin signo será igual al rango del tipo de entero con signo correspondiente, si lo hay.
    • El rango de cualquier tipo de entero estándar será mayor que el rango de cualquier tipo de entero extendido con el mismo ancho.
    • El rango de char será igual al rango de signed char y unsigned char .
    • El rango de cualquier tipo entero con signo extendido en relación con otro tipo entero con signo extendido con la misma precisión está definido por la implementación pero aún está sujeto a las otras reglas para determinar el rango de conversión entero.
    • Para todos los tipos enteros T1, T2 y T3, si T1 tiene un rango mayor que T2 y T2 tiene un rango mayor que T3, entonces T1 tiene un rango mayor que T3.
  • Conversiones aritméticas habituales:

    • Si ambos operandos tienen el mismo tipo, no se necesita ninguna otra conversión.
    • Si ambos operandos son del mismo tipo entero (firmado o no), el operando con el tipo de rango de conversión entero menor se convierte al tipo del operando con mayor rango.
    • Si el operando que tiene un tipo entero sin signo tiene un rango mayor o igual que el rango del tipo del otro operando, el operando con tipo entero con signo se convierte al tipo del operando con tipo entero sin signo.
    • Si el tipo del operando con tipo entero con signo puede representar todos los valores del tipo del operando con tipo entero sin signo, el operando con tipo entero sin signo se convierte al tipo del operando con tipo entero con signo.
    • De lo contrario, ambos operandos se convierten al tipo de entero sin signo correspondiente al tipo de operando con tipo de entero con signo. Las operaciones específicas pueden agregar o modificar la semántica de las operaciones aritméticas habituales.

Todo el capítulo 4 habla sobre las conversiones, pero creo que deberían estar más interesados ​​en esto:

4.5 Promociones integrales [conv.prom]
Un rvalue de tipo char, signed char, unsigned char, short int o unsigned short int se puede convertir a un rvalue de tipo int si int puede representar todos los valores del tipo de fuente; otro-
sabio, el valor de fuente se puede convertir a un valor de r de tipo unsigned int.
Un valor rval de tipo wchar_t (3.9.1) o un tipo de enumeración (7.2) se puede convertir a un valor de r de la primera
de los siguientes tipos que pueden representar todos los valores de su tipo subyacente: int, unsigned int,
largo, o sin signo largo.
Un valor de r para un campo de bits integral (9.6) se puede convertir a un valor de r de tipo int si int puede representar todos
los valores del campo de bit; de lo contrario, se puede convertir a unsigned int si unsigned int puede representar
resent todos los valores del campo de bit. Si el campo de bit es aún más grande, no se aplica ninguna promoción integral. Si el
bit-field tiene un tipo enumerado, se trata como cualquier otro valor de ese tipo para fines de promoción.
Un rvalue de tipo bool se puede convertir a un rvalue de tipo int, con false convirtiéndose en cero y verdadero
convirtiéndose en uno
Estas conversiones se llaman promociones integrales.

4.6 Promoción de punto flotante [conv.fpprom]
Un valor de rvalue de tipo float se puede convertir a un rvalue de tipo double. El valor no ha cambiado.
Esta conversión se llama promoción de coma flotante.

Por lo tanto, todas las conversiones que implican float: el resultado es flotante.

Solo el que involucra ambos int – el resultado es int: int / int = int

El tipo de expresión, cuando no ambas partes son del mismo tipo, se convertirá al más grande de ambos. El problema aquí es comprender cuál es más grande que el otro (no tiene nada que ver con el tamaño en bytes).

En expresiones en las que están involucrados un número real y un número entero, el número entero se promoverá a un número real. Por ejemplo, en int + float, el tipo de expresión es flotante.

La otra diferencia está relacionada con la capacidad del tipo. Por ejemplo, una expresión que implica un int y un int largo resultará de tipo long int.

¡Advertencia!

Las conversiones ocurren de izquierda a derecha.

Prueba esto:

 int i = 3, j = 2; double k = 33; cout << k * j / i << endl; // prints 22 cout << j / i * k << endl; // prints 0