2016-06-21 14 views
5

Ho un pezzo di codice in cui moltiplico due numeri ma la condizione è nessuno di quei numeri interi dovrebbe essere 0. Se è 0, ho bisogno per renderlo a 1 in modo che non venga contato.Qual è il modo più ottimale per sostituire l'intero '0' con '1' in C++

y=x*z // x>0, z>0. if x==0 then x=1, if z==0, then z=1; 

voglio evitare "se" condizione di controllo su tutte le variabili e sostituirlo con 1. Esiste un modo migliore di farlo.

+2

non fare questo 'x? z? x * z: x: z? z: 1' –

+2

Stai cercando di evitare un 'if' a livello sintattico o sei stanco del ramo nel codice macchina generato? Perché tutte le soluzioni con '' 'nascondono semplicemente il ramo sotto il tappeto (il' if' è ancora lì, l'hai appena camuffato con una sintassi diversa). –

+0

Cosa c'è di sbagliato: 'assert (x! = 0); assert (z! = 0); 'e assicurandoti che le asserzioni non si attivino mai? In altre parole, perché accetti dati falsi? Perché non respingere forzatamente dati errati? E che succede con: 'y = x * z; if (y == 0) y = 1; 'che controlla solo il risultato, non gli operandi? Se la risposta è per 'x == 0 && z == 2' il valore in' y' dovrebbe essere 2, quindi dovresti dire tanto nella domanda. –

risposta

1

Se uno di essi è poi 0 Inoltre vi darà lo stesso risultato come se si cambia 0 al 1

y = (x * z > 0 ? x * z : x + z) 
+2

non se entrambi x e z sono 0 –

+1

Quanto sopra non funzionerà se x o z è negativo. Dovrebbe essere 'y = ((x * z == 0)? X + z: x * z)' –

15

seguito

y=(x==0?1:x)*(z==0?1:z) 

vi darà questo codice [ assembly ].


e un adattamento preso in prestito dal commento @Jerry Coffin s' al suo [ answer ]

y=(x+(x==0))*(z+(z==0)); 

vi darà questo codice [ assembly ].

+1

Genera il più piccolo [Assembly] (https://gcc.godbolt.org/#compilers :! ((compilatore : G530, opzioni: '- std% 3Dc% 2B% 2B14 + -O3', fonte: 'int + main (int + i, + char ** g)% 0A% 7B% 0A ++ int + x +% 3D + * g % 5B0% 5D% 3B% 0A ++ int + z +% 3D + * g% 5B1% 5D% 3B% 0A ++ ritorno + (x% 3D% 3D0% 3F1: x) * (z% 3D% 3D0% 3F1: z)% 3B% 0A% 7D ')), filterAsm: (commentOnly:! t, direttive:! t, etichette:! t), la versione: 3). – Viatorus

+0

@Viatorus: aggiornata la risposta. :) – sjsam

+0

mmm. Probabilmente dovresti controllare l'assemblaggio più piccolo con -O2 ... –

6

Sinceramente, dubito che si potrebbe arrivare a un modo che sarebbe significativamente sottoperformante. Scegli qualcosa che puoi leggere più tardi invece di qualcosa che ritieni sia il più veloce. È probabile che questa operazione specifica non sarà un collo di bottiglia.

+1

O sta cercando un codice chiaro e conciso, nel qual caso il tuo commento non aiuta molto. –

+2

Vi sfido a quantificare i vantaggi di leggibilità di una soluzione "chiara e concisa" rispetto all'ovvia soluzione a due condizionali. – zneak

9
y = (!x^x) * (!z^z); 

Questo funziona perché quando si xo un numero con 0, si ottiene lo stesso numero indietro. Quindi se x != 0, quindi !x == 0 e !x^x equivale a 0^x, che è x. E se x == 0, poi !x == 1, e !x^x equivale a 1^0, che è 1.

+5

Più 1 per soddisfare tutti i requisiti, -999 per tutti quelli che in realtà lo codificano nella vita reale. –

+0

Richiede altre due istruzioni xor in contrasto con @sjsam. [Assembly] (https://gcc.godbolt.org/#compilers :! ((compilatore: G530, opzioni: '- std% 3Dc% 2B% 2B14 + -O3', fonte: 'int + main (int + i, + char ** g)% 0A% 0A ++ int + x +% 3D + * g% 5B0% 5D% 3B% 0A ++ int + z +% 3D + * g% 5B1% 5D% 3B% 0A ++ ritorno + (7B% !! x +% 5E + x) + * + (!! z +% 5E + z)% 3B% 0A% 7D ')), filterAsm: (commentOnly:! t, direttive:! t, etichette:! t), la versione : 3). – Viatorus

+0

@Viatorus: il numero di istruzioni di assemblaggio generate è spesso una metrica inutile per quanto riguarda le prestazioni. I compilatori hanno generalmente due flag mutualmente esclusivi per il codice fast vs small. –

3

non ho certamente intenzione di garantire che avrà effetti positivi sul vostro codice, ma una possibilità potrebbe essere qualcosa di simile :

x += int(x == 0); 
z += int(z == 0); 

Ciò confronta la variabile a 0, producendo false o true. Viene quindi convertito in un valore, fornendo 0 se il valore era precedentemente diverso da zero e 1 se era zero. Quindi aggiungiamo quel risultato alla variabile, quindi se fosse zero, ne aggiungeremo uno, dando 1. Se fosse un valore diverso da zero, aggiungiamo zero ad esso, che ovviamente non influenza il suo valore.

+1

Oppure ... 'x + =! X;' –

+0

Bello, ma non penso che l'op desideri effettivamente cambiare la variabile qui sebbene abbiano menzionato 'Ho bisogno di renderlo a 1'. Il cambiamento è solo per l'operazione. – sjsam

+0

@CareyGregory: Bello !! – sjsam

2
y=max(x,1)*max(z,1); 

Definire la funzione max se necessario da #define parola chiave del preprocessore o come una funzione normale.

-2

Se sei preoccupato per i risultati precisi, allora dovresti usare la dichiarazione if che hai nel tuo commento o l'operatore ternario ? come la maggior parte delle persone suggerisce.
Se semplicemente preoccupate perché non vi siano filiali in questa sezione di codice è sempre possibile o 1:

x = x | 1; 
z = z | 1; 
y = x * z; 

Questo sarebbe garanzia che non ci sarebbero filiali in questo codice e che né x o z sono tutti uguale a 0. Ma il prezzo da pagare è la precisione, dal momento che si può sempre accidentalmente aggiungere 1 a uno x o z:

00000000 | 1 = 1 
10001011 | 1 = 10001011 
10101010 | 1 = 10101011 <- imprecision introduced! 
+6

2 * 2 == 9 è un bel po 'di imprecisione .... –

1

funzionerà

y = (x x:? 1)? * (Z z: 1)

0

Bene, ho usato il collegamento da this answer e creato tale codice. assembly here, l'assemblaggio è più breve, quindi potrebbe essere più veloce, ma richiede profilazione, perché l'assemblaggio più corto potrebbe non essere più veloce.

int main(int i, char**g) 
{ 
    int x = *g[0]; 
    int z = *g[1]; 
    int tmp = z ? 1 : z; 
    return (x==0?tmp:x*tmp); 
} 
Problemi correlati