Booleano-Integer Tipo per sostituire condizionale [chiuso]

0

Quando si sceglie un valore basato su 2 valori booleani in questo formato

var foo:int;

if (X){
    foo = 50;
} else if (Y){
    foo = -50;
} else {
    foo = 0;
}

Ho scoperto che posso condensare in questo modo convertendo le operazioni booleane in numeri interi, e matemandolo un po 'in questo modo:

var foo:int;

foo = ( int (X) - int(!X && Y) ) * 50;
// int() typecasts a boolean argument to an int of 1 if true, 0 if false.

Ecco le mie domande:

  1. Questo approccio richiede meno risorse?
  2. Questo approccio è leggibile per te?
  3. Assegnare valori in questo modo è comune?
  4. Se 1 è vero, secondo te, l'aumento delle prestazioni giustifica la natura meno leggibile di questo approccio?

Questa situazione è sorto in ActionScript 3.0, ma sono interessato a risposte da tutte le lingue e da una prospettiva di best practice.

    
posta Kris Welsh 23.03.2013 - 23:50
fonte

2 risposte

6

Questa è in una certa misura una questione di stile, ma credo davvero che la tua opzione a linea singola sia molto, molto meno leggibile e non sia un approccio comune.

Il primo classico if è molto facile da leggere e controllare. Non esiste una nidificazione complessa, solo una semplice, "noiosa" catena di condizioni che è ben compresa in tutte le lingue che hanno un costrutto if/else if/else .

Il secondo è molto complicato:

  • Due condizionali, uno di questi è un composito per il quale è necessario conoscere la precedenza degli operatori
    !X && Y interpretato come (!X) && Y o !(X && Y) )
  • Due cast per i quali è necessario sapere che true viene convertito in 1 e false in 0 (o sono quelle chiamate di funzione?). Questo potrebbe essere comune, ma è qualcosa di cui le persone non sono sempre consapevoli, o consapevoli del fatto che la lingua lo garantisce. (Questo significa che se in questo esempio utilizzi un cast incorporato, se si tratta di una chiamata di funzione personalizzata, è necessario conoscere anche questo)
  • Quindi devi capire quale sarà il risultato di quell'operazione - in quali circostanze. Matematica piuttosto elementare, ma richiede alcuni cicli cerebrali più della banale if/else cascade.

Per quanto riguarda la seconda versione potrebbe in qualche modo essere più efficiente? Io non la penso così In effetti, potrebbe non essere solo meno efficiente, ma non comportarsi allo stesso modo del primo. X viene valutato due volte (quindi potenzialmente più costoso). Se la valutazione di X ha effetti collaterali, le due versioni non sono equivalenti.

(E non menzioniamo le macro di tipo C che potrebbero interrompere la seconda versione mentre il primo funziona, oi problemi con le operazioni non sequenziate che la seconda versione potrebbe comportare in C e C ++ a causa di questa doppia valutazione in una singola istruzione - Non penso che questo sia il punto della tua domanda qui.)

tl; dr : meno righe di codice non significano più efficienti. Il tuo codice dovrebbe essere scritto in modo che possa essere mantenuto in modo efficiente. Il tuo compilatore / runtime / interprete si prenderà cura dello sporco lavoro di ottimizzazione purché tu abbia scelto i giusti algoritmi e strutture dati e li abbia espressi chiaramente nella tua lingua.

    
risposta data 24.03.2013 - 00:57
fonte
2

Is this approach less resource intensive?

Ho scritto due semplici bit di C e ho esaminato il disassemblaggio di ciascuno.

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char x = argv[1][0] == 't';
    char y = argv[1][1] == 't';
    int foo;

    if(x) {
        foo = 50;
    } else if (y) {
        foo = -50;
    } else {
        foo = 0;
    }

    printf("%d",foo);
    return 0;
}

e

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char x = argv[1][0] == 't';
    char y = argv[1][1] == 't';
    int foo = ( x - (!x && y) ) * 50;

    printf("%d",foo);
    return 0;
}

Scusa i miei dissasemblati, sono su un Mac piuttosto che su un Linux Box e quindi non ho un facile accesso a gcc -S quindi non li incollerò qui. Osservando la sequenza di eventi in ciascuna di esse si trovano le istruzioni if o l'espressione:

Questa sequenza nella prima è:
cmpb je movl jmp cmpb je movl jmp movl jmp leaq movl movb
Lo stesso reigon nella seconda versione è:
movsbl cmpb movl movb jne movsbl cmpl setne movb movb leaq andb movzbl movl subl imull movl movl movb

Il primo è possibile vedere il confronto, saltare uguale, assegnare, saltare alla fine, confrontare, saltare uguale, assegnare, saltare alla fine, assegnare. Nel secondo, c'è una quantità significativa di operazioni in corso. Si può vedere andb , subl e imull che fanno operatori aritmetici.

Il primo farà un piccolo numero di confronti con costanti e rami. Il secondo fa un numero significativo di operazioni.

Is this approach readable to you?

Il primo è di gran lunga più leggibile e mantenibile. Anche se il secondo fosse quello di produrre un codice più ottimale, scriverei ancora il primo perché le frazioni di un secondo che vengono salvate nel codice vengono perse molte volte quando qualcuno torna per mantenere il codice e va in WTF?!

Is assigning values in this way common?

No. Non l'ho mai visto prima di questa situazione.

If 1 is true then in your opinion, does the performance increase justify the less readable nature of this approach?

Come ho detto, la manutenibilità del codice è fondamentale in ogni situazione in cui qualcun altro possa mai avere la gioia di toccare il tuo codice in seguito.

Come programmatore di Perl, riconosco il valore di hubris:

Hurbis: Excessive pride, the sort of thing Zeus zaps you for. Also the quality that makes you write (and maintain) programs that other people won't want to say bad things about. Hence, the third great virtue of a programmer.

So che direi cose cattive su un programmatore che scrive il secondo, quindi non ho intenzione di farlo.

    
risposta data 28.03.2013 - 01:19
fonte

Leggi altre domande sui tag