2011-11-20 14 views
11

Ciao a tutti stavo dando un'occhiata agli parte del codice sorgente di Java, quando mi sono imbattuto in questo (java.lang.Character):char_x <(char_y + 1) == char_x <= char_y?

public static boolean isHighSurrogate(char ch) { 
    return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1); 
} 

public static boolean isLowSurrogate(char ch) { 
    return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1); 
} 

Mi chiedevo perché ha fatto lo scrittore ha aggiunto 1 al limite più alto e facendo un meno di confrontare , invece di fare semplicemente un confronto minore o uguale?

Posso capire se aiuta la leggibilità, ma in questo caso non sembra essere il caso.

Mi chiedevo che cosa è la differenza tra il codice qui sopra e questo:

public static boolean isHighSurrogate(char ch) { 
    return ch >= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE; 
} 

public static boolean isLowSurrogate(char ch) { 
    return ch >= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE; 
} 
+0

Questa è un'ipotesi, non una risposta: forse deve essere coerente con il modo idiomatico di scrivere per loops, ad es. 'for (i = LOWER_BOUND; i

+0

Forse voleva sottolineare che ch può anche essere uguale a MAX_ [HIGH | LOW] _SURROGATE. "<=" è più facile da leggere come "<" - e il compilatore probabilmente lo ottimizza comunque nello stesso bytecode. –

+2

Beh, per prima cosa, 'MAX_HIGH_SURROGATE' è un char e' 1' è un int ... potrebbe esserci qualche tipo di conversione da char a int andando lì che potrebbe essere necessario. – BoltClock

risposta

2

Forse l'autore sta cercando di essere coerenti con Dijkstra's advice per fare tutte le gamme semiaperta - il punto di partenza è inclusiva e la l'endpoint è esclusivo.

Non v'è alcuna differenza semantica qui, ma una sottile differenza in bytecode: (ch + 1) è un int così il primo frammento di codice fa un char per char confronto seguita da un int per int confronto mentre la seconda fa due char a char confronti. Questo non porta a una differenza semantica: i cast impliciti sono di tipo più ampio e quindi non c'è il rischio di overflow in entrambi i frammenti di codice.

Ottimizzare l'addizione e la conversione del confronto int a int di nuovo in un 2 byte senza segno confronto int è ben nell'ambito dei tipi di ottimizzazioni fatte dal JIT quindi non vedo alcuna ragione particolare per le prestazioni di preferire una sull'altro.

tendo a scrivere questo genere di cose come

MIN_LOW_SURROGATE <= ch && ch <= MAX_LOW_SURROGATE 

così il ch nel mezzo rende evidente ad un lettore che il ch viene controllata una all'interno della gamma dei valori esterni.

+0

Avrei pensato che avrebbe avuto più senso se avesse usato lo stesso confronto per entrambi i lati: 'ch> = (MIN_HIGH_SURROGATE + 0) && ch <(MAX_HIGH_SURROGATE + 1)' – Pacerier

+0

@Pacerier, ci sono molti modi sottilmente diversi per dire la stessa cosa. Sceglerei quello che fa underflow/overflow e gli errori "off-by-1" spiccano su di te e restano fedeli. –

0

Direi che non c'è davvero alcuna differenza tra i due modi di codificarlo, è solo una questione di gusti ciò che preferiresti, dal momento che non hai davvero alcun vantaggio di una delle due diverse implementazioni.

Mi chiedevo perché lo scrittore ha aggiunto 1 al limite superiore e facendo un confronto minore di quello, invece di fare semplicemente un confronto minore o uguale?

Voglio dire, perché preferiresti la seconda scelta? Mi manca qualcosa qui?

+0

Voglio dire, non è la seconda scelta più leggibile (ha più senso logico) anche a te? – Pacerier

+0

No, in realtà non dal momento che mi aspetterei una differenza di almeno 1 tra MAX e MIN e il + 1 lo fa per me, ma questo è solo il mio pov. – philomatic

-1

Perché l'autore era un C++ o un montatore.

È più veloce eseguire un> = di> ed è più veloce da eseguire < = rispetto a <. In realtà, quando scrivi un < b il compilatore crea un < = b + 1, quindi esegue un'aggiunta e un confronto, perché l'unica istruzione di assemblaggio disponibile è < =. Se scrivi questa somma nel codice a mano, un compilatore C++ cambierà MIN_HIGH_SURROGATE + 1 con il valore effettivo del risultato al momento della compilazione. Quindi ottieni un'istruzione e un ciclo.

Ma tutto questo strano ragionamento si applica solo per codice compilato, come C++ o C. O ASM.

EDIT

Anche se ci sono le istruzioni per ciascuno degli operatori di uguaglianza di cui sopra (mi sbagliavo), tutte si riducono a sottrazioni e aggiunte in microcodice (se necessario). Quindi il processore controlla il bit del segno del risultato. Quindi la formulazione del codice sopra sarà ancora più veloce.

Per assicurarsi che non vi siano overflow quando si aggiunge 1, il microprocessore prima sottrae, quindi ne aggiunge uno.

+0

Con questa logica, se 'b' è MAX_VALUE, allora non significherebbe che' a Pacerier

+0

Devi assicurarti che non accada. È il lavoro del programmatore. – Sam

+0

Su x86, almeno, ci sono le istruzioni per '<=' e '<'. Lo stesso per bytecode Java. Nessuno dei due dovrebbe essere più veloce dell'altro. Di conseguenza, dubito che il compilatore converta l'uno nell'altro. –

2

supposizione

carattere Surrogate, qualsiasi di una serie di codepoints Unicode che sono usato in coppie in UTF-16 per rappresentare i caratteri al di là della base Multilingual Plane.

Dal mio punto di vista voleva ignorare roba da 8 bit, ovvero se il massimo era 0xFF. 0xFF + 1 andrebbe in overflow e tornerebbe a 0x00. Rendere il confronto sempre falso.

Quindi se il codice è stato compilato con caratteri di 8 bit. Resterebbe sempre falso (al di fuori dell'intervallo UTF-16) mentre se compila un char in> 8 bit l'0xFF + 1 sarebbe 0x100 e funzionerà ancora.

Spero che questo abbia un certo senso per te.

+0

'char' è sempre un numero intero a 16 bit senza segno in java. Il massimo è 0xDBFF e il minimo è 0xD800. –

Problemi correlati