2010-02-13 6 views
10

Considerate questo codice:Perché il tipo risultante di una divisione di interi brevi in ​​Java non è un intero breve?

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

compilazione di questo genera l'errore

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

perché il tipo dell'espressione i/j è apparentemente int, e quindi deve essere gettato a breve.

Perché il tipo di i/j non è breve?

+1

Poiché la conversione di una int in una breve darebbe una possibile perdita di precisione. (-32768/-1) –

risposta

16

Dal Java spec:

5.6.2 Binary numerico Promozione

Quando un operatore applica promozione numerico binario ad una coppia di operandi, ciascuno dei quali deve indicare un valore di tipo numerico, la si applicano le seguenti regole, in ordine, utilizzando la conversione di allargamento (§5.1.2) per convertire gli operandi come necessario:

Se uno degli operandi è di tipo double, l'altro viene convertito in double.

Altrimenti, se uno degli operandi è di tipo float, l'altro viene convertito in float.

Altrimenti, se uno degli operandi è di tipo lungo, l'altro viene convertito in long.

In caso contrario, entrambi gli operandi vengono convertiti in tipo int.

Per operazioni binarie, piccoli tipi interi sono promossi al int e il risultato dell'operazione è int.


EDIT: Perché è così? La risposta breve è che Java ha copiato questo comportamento da C. Una risposta più lunga potrebbe avere a che fare con il fatto che tutte le macchine moderne eseguono almeno calcoli nativi a 32 bit, e potrebbe essere più difficile per alcune macchine fare a 8 bit e Operazioni a 16 bit.

Consulta anche: OR-ing bytes in C# gives int

+0

ulteriore: promozione numerica binaria viene eseguita sugli operandi di determinati operatori: - Gli operatori moltiplicativi *,/e% – akf

+0

OK, ho capito che le specifiche del linguaggio dicono che la lingua dovrebbe comportarsi come questo (altrimenti il ​​compilatore non genererebbe l'errore in primo luogo). Ma non capisco la motivazione che sta dietro. Perché stanno promuovendo i tipi prima di fare la divisione invece di dividere i pantaloncini? – flodin

+0

La mia scommessa è "così com'è in C". Java è stato progettato per essere attraente per i programmatori C++, che richiede che le cose siano le stesse –

2

Per quanto riguarda la motivazione: lascia immaginare le alternative a questo comportamento e vedere il motivo per cui non funzionano:

Alternativa 1: il risultato dovrebbe essere sempre lo stesso come gli ingressi .

Quale dovrebbe essere il risultato di aggiungere un int e un breve?

Quale dovrebbe essere il risultato per moltiplicare due cortocircuiti? Il risultato in generale si inserirà in un int, ma poiché tronceremo in breve, la maggior parte delle moltiplicazioni fallirà silenziosamente. Il casting su un int dopo non ti aiuterà.

Alternativa 2: il risultato deve sempre essere il tipo più piccolo che possa rappresentare tutte le uscite possibili.

Se il tipo di reso fosse breve, la risposta non sarebbe sempre rappresentabile come un breve.

Un corto può contenere valori da -32.768 a 32.767. Quindi questo risultato causerà un overflow:

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

Quindi la domanda diventa: perché l'aggiunta di due ints non restituisce un lungo? Quale dovrebbe essere la moltiplicazione di due interi? Lungo? Un numero grande per coprire il caso del valore minimo dell'intero quadrante?

Alternativa 3: scegliere la cosa maggior parte delle persone probabilmente vogliono la maggior parte del tempo

Così il risultato dovrebbe essere:

  • int per moltiplicare due cortometraggi, o qualsiasi int operazioni.
  • short se si aggiungono o si sottrae cortocircuiti, dividendo un cortocircuito di un qualsiasi tipo intero, moltiplicando due byte, ...
  • byte se il bithifting è un byte a destra, int se si sposta a sinistra.
  • ecc ...

Ricordando tutti i casi particolari sarebbe difficile se non v'è alcuna logica fondamentale per loro. È più semplice dire semplicemente: il risultato di operazioni intere è sempre int.

+0

Quello che le persone vogliono, non è sempre lo stesso di quello che è una buona idea se lo hai progettato di nuovo. Un buon esempio è la disposizione della tastiera QWERTY. Originariamente progettato per * rallentare * i dattilografi in modo che le macchine da scrivere non si blocchino. Tuttavia, non posso immaginare di usare qualcos'altro come mi sono abituato. –

+0

@Peter Lawrey: Sì. Se Henry Ford avesse chiesto alle persone che tipo di macchina dovesse fabbricare, molti avrebbero chiesto un carrello con ** 6 ** cavalli anziché 4. Ascoltare ciò che i tuoi utenti desiderano è una buona cosa, ma a volte devi dare loro sono qualcosa di diverso da quello che vogliono perché non sono nemmeno in grado di immaginare una soluzione diversa da quella a cui sono abituati. –

+0

Per le lingue senza sovraccarico dell'operatore, perché il risultato non è il più piccolo (massimo risultato possibile) o (dimensione del contenitore ricevente)? Nella maggior parte dei casi, una tale regola produrrebbe un codice che fosse il più piccolo o più piccolo di qualsiasi cosa che potesse essere espressa in grado di produrre risultati aritmetici corretti usando l'approccio n. 1. Ad esempio, se le variabili sono 32 bit, 'p = (x * y)/z;' farebbe una moltiplicazione 32x32-> 64 e una divisione 64/32-> 32. Se 'p' e' z' fossero 16 bit, farebbero una moltiplicazione 32x32-> 64, una riduzione di 64-> 32 overflow e una divisione 32/16-> 16. – supercat

0

E 'solo una scelta progettuale per essere coerente con C/C++ che erano le lingue dominate quando Java è stato progettato.

Ad esempio, i * j potrebbe essere implementato in modo che il tipo venga promosso da byte => short, short => int e int => long, e ciò eviterebbe gli overflow ma non lo fa. (Lo fa in alcune lingue) La fusione può essere usata se si desidera il comportamento corrente, ma la perdita di alcuni bit sarebbe chiara.

Analogamente, i/j potrebbe essere richiesto da byte/short => float o int/long => double.

Problemi correlati