2010-02-13 4 views
10

consideran este código:¿Por qué el tipo resultante de una división de enteros cortos en Java no es un entero corto?

public class ShortDivision { 
    public static void main(String[] args) { 
     short i = 2; 
     short j = 1; 
     short k = i/j; 
    } 
} 

Compilar esto produce el error

ShortDivision.java:5: possible loss of precision 
found : int 
required: short 
     short k = i/j; 

porque el tipo de la expresión i/j es aparentemente INT, y por lo tanto deberán ser emitidos a corto.

¿Por qué el tipo de i/j no es corto?

+1

Porque convertir un int en un corto daría una posible pérdida de precisión. (-32768/-1) –

Respuesta

16

Desde el Java spec:

5.6.2 numérico binario Promoción

Cuando un operador aplica promoción numérica binaria a un par de operandos, cada uno de los cuales debe denotar un valor de un tipo numérico, el Las siguientes reglas se aplican, en orden, usando conversión de ampliación (§5.1.2) para convertir operandos según sea necesario:

Si cualquier operando es de tipo doble, el otro se convierte a doble.

De lo contrario, si cualquiera de los operandos es del tipo float, el otro se convierte en float.

De lo contrario, si cualquiera de los operandos es de tipo largo, el otro se convierte en largo.

De lo contrario, ambos operandos se convierten en tipo int.

Para las operaciones binarias, pequeños tipos enteros son promovidos a int y el resultado de la operación es int.


EDIT: ¿Por qué es así? La respuesta corta es que Java copió este comportamiento de C. Una respuesta más larga podría tener que ver con el hecho de que todas las máquinas modernas hacen al menos cálculos nativos de 32 bits, y en realidad podría ser más difícil para algunas máquinas hacer 8 bits y Operaciones de 16 bits.

Consulte también: OR-ing bytes in C# gives int

+0

adicional: La promoción numérica binaria se realiza en los operandos de ciertos operadores: - Los operadores multiplicativos *,/y% – akf

+0

Bien, entiendo que la especificación del lenguaje dice que el lenguaje debe comportarse así (de lo contrario, el compilador no generaría el error en primer lugar). Pero no entiendo la motivación detrás de eso. ¿Por qué están promocionando los tipos antes de hacer la división en lugar de simplemente dividir los cortos? – flodin

+0

Mi apuesta es "así es en C". Java fue diseñado para ser atractivo para los programadores de C++, que requiere que las cosas sean las mismas –

2

En cuanto a la motivación: Imaginemos que las alternativas a este comportamiento y ver por qué no funcionan:

Alternativa 1: el resultado siempre debe ser el mismo que las entradas .

¿Cuál debería ser el resultado de agregar un int y un short?

¿Cuál debería ser el resultado de multiplicar dos pantalones cortos? El resultado en general se ajustará a un int, pero como truncamos a corto, la mayoría de las multiplicaciones fallarán en silencio. Casting a un int después no ayudará.

Alternativa 2: el resultado siempre debe ser el tipo más pequeño que pueda representar todas las salidas posibles.

Si el tipo de devolución fue corto, la respuesta no siempre podría ser representativa.

Un valor bajo puede contener valores -32,768 a 32,767. Entonces, este resultado causará desbordamiento:

short result = -32768/-1; // 32768: not a short 

Así que su pregunta es: ¿por qué la adición de dos ints no devuelve un largo? ¿Qué debería ser la multiplicación de dos puntos? Un largo? ¿Un BigNumber para cubrir el caso de cuadrar el valor mínimo entero?

Alternativa 3: Elija lo más probable que las personas quieren mayor parte del tiempo

Así, el resultado debería ser:

  • int para multiplicar dos cortos, o cualquier operaciones int.
  • corto si se suman o restan cortos, dividiendo un corto por cualquier tipo de entero, multiplicando dos bytes, ...
  • byte si bitshifting un byte a la derecha, int si bitshifting a la izquierda.
  • etc ...

recordando todos los casos especiales serían difíciles si no hay una lógica fundamental para ellos. Es más simple decir: el resultado de operaciones enteras es siempre un int.

+0

Lo que la gente quiere, no siempre es lo mismo que lo que es una buena idea si lo diseñaste de nuevo. Un buen ejemplo es la disposición del teclado QWERTY. Originalmente diseñado para * ralentizar * mecanógrafos para que las máquinas de escribir no se atasquen. Aún así, no puedo imaginar usar cualquier otra cosa ya que estoy acostumbrado. –

+0

@ Peter Lawrey: Sí. Si Henry Ford le hubiera preguntado a la gente qué tipo de automóvil debería fabricar, muchos habrían estado pidiendo un carrito con ** 6 ** caballos en lugar de 4. Escuchar lo que quieren los usuarios es algo bueno, pero a veces hay que dar algo diferente de lo que quieren porque ni siquiera son capaces de imaginar una solución diferente a la que están acostumbrados. –

+0

Para idiomas sin sobrecarga del operador, ¿por qué no tener el resultado más pequeño (mayor resultado posible) o (tamaño del contenedor receptor)? En la mayoría de los casos, dicha regla arrojaría un código que era tan pequeño o más pequeño que cualquier cosa que se pudiera expresar que arrojaría resultados aritméticamente correctos usando el enfoque n. ° 1. Por ejemplo, si las variables son 32 bits, 'p = (x * y)/z;' harían una multiplicación de 32x32-> 64 y una división de 64/32-> 32. Si 'p' y' z' fueran 16 bits, harían una multiplicación de 32x32-> 64, una reducción comprobada de desbordamiento de 64-> 32 y una división de 32/16-> 16. – supercat

0

Es solo una opción de diseño para ser coherente con C/C++, que eran los idiomas dominantes cuando se diseñó Java.

Por ejemplo, i * j podría implementarse de modo que el tipo se promueva desde byte => short, short => int, e int => long, y esto evitaría los desbordamientos pero no lo hace. (Lo hace en algunos idiomas). Se podría usar la conversión si se deseaba el comportamiento actual, pero la pérdida de algunos bits sería clara.

De manera similar, se podría solicitar i/j desde byte/short => float o int/long => double.

Cuestiones relacionadas