Confronta due numeri interi in C o C ++ senza operatori di confronto


12

Produce il programma più breve che accetta due numeri interi con segno come input (tramite stdin o come argomenti) e visualizza 3 output diversi a seconda che il primo numero sia (1) maggiore di, (2) più piccolo di, o (3) uguale al secondo numero.

La presa

Non è possibile utilizzare nessuna delle seguenti opzioni nel programma:

  • Gli operatori di confronto standard: <, >, <=, >=, ==, !=.
  • Qualsiasi file di libreria a parte conio, stdioo iostream.
  • Qualsiasi carattere ASCII non ASCII o non stampabile.

Il vincitore

Vince il programma con il minor numero di caratteri.


Suppongo che usare cose come abs senza includere il file di libreria (perché il compilatore lo sappia comunque) non è permesso neanche?
Martin Ender,

1
@ MartinBüttner sì, sarebbe un presupposto corretto. :)
Grove

5
Perché la restrizione a C (++)? Se è perché vuoi che le risposte siano portatili nonostante la non portabilità dei tipi di base di C, allora dovresti affermarlo. Se si tratta di una restrizione arbitraria, dovresti essere consapevole che le restrizioni arbitrarie a una lingua sono impopolari su questo sito.
Peter Taylor,

8
@PeterTaylor fa parte della sfida. Sarebbe un gioco molto diverso se la domanda fosse agnostica. La limitazione a C / C ++ modifica le strategie utilizzate per affrontare il problema. Riconosco la necessità che le domande siano aperte alla maggior parte delle lingue per promuovere la partecipazione di più persone, ma in questo particolare problema la restrizione a C / C ++ e ai loro operatori e metodi specifici è parte integrante della sfida.
Grove

1
@EvilTeach yes; se qualcosa non è esplicitamente vietato nella domanda, allora è permesso.
Grove

Risposte:


2

53 byte

main(a,b){scanf("%d%d",&a,&b);printf("%ld",0l+a-b);}

È rilevante solo il primo carattere dell'output. Le tre diverse uscite sono:

  1. '-' se b> a
  2. '0' se a == b
  3. qualsiasi altro carattere se a> b

Funziona per l'intero intervallo di input di int su tutte le piattaforme in cui sizeof (long)> sizeof (int).

Modifica: costa un carattere in più per fare in modo che il caso 3 stampi un '+' in modo univoco invece:

main(a,b){scanf("%d%d",&a,&b);printf("%+ld",0l+a-b);}

6

Forse mi manca qualcosa nelle regole, ma ...

81 byte

main(a,b){scanf("%d%d",&a,&b);long long l=a;l-=b;printf("%lld%d",--l>>63,l>>63);}

Ouputs 00if a > b, -10if a == be -1-1if a < b.


Per quanto sia comune questo tipo di codice, C non garantisce che funzioni. long longpotrebbe essere superiore a 64 bit, intpotrebbe essere grande in modo da poter traboccare, il risultato del corretto spostamento dei valori negativi è definito dall'implementazione. Praticamente tutte le risposte derivate dal C hanno problemi simili.
Yann Vernier,

1
@YannVernier: Capito. Immagino che una soluzione infallibile al 100% sarebbe un mostro, dal momento che l'unica cosa che potremmo fare in sicurezza (cioè senza spostamento o trabocco) è un po 'a spirale, e per farlo in sicurezza avremmo bisogno di determinare la lunghezza degli operandi usando sizeof.
COTO

6

90 byte

Se possiamo usare stdio, perché non usare le sue capacità di formattazione per eseguire il confronto?

main(a,b){scanf("%d%d",&a,&b);snprintf(&a,2,"%d",b-a);a&=63;putchar(51-!(a-45)-!!(a-48));}

Presuppone la codifica compatibile ASCII e la little-endianness.

72 byte

I quotienti sono arrotondati a zero ma i turni a destra sono (in pratica) "arrotondati per difetto". È un omaggio morto.

main(a,b){scanf("%d%d",&a,&b);a-=b;putchar(a?a|=1,a/2-(a>>1)?60:62:61);}

65 79 byte

Un'altra proprietà distintiva dei numeri negativi è che producono un modulo negativo. Questo non dipende affatto dalla rappresentazione dei numeri interi; funziona anche con il mio tostapane 8-bit 8-bit in eccesso! Oh, e dal momento che possiamo usare conio, perché non salvare due byte con putch? Ora, se solo potessi trovare la mia copia di TurboC ...

main(a,b){scanf("%d%d",&a,&b);long long d=a;d-=b;putch(d?d|=1,d%2-1?60:62:61);}

EDIT : gestire grandi differenze assumendo che long longsia più ampio di int.


Sono abbastanza sicuro che hai bisogno di un delimitatore tra le %ds nel tuo scanfper analizzare in modo inequivocabile due numeri interi. Bella idea però!
Martin Ender,

1
@Martin: Beh, funziona con GCC, ma non sono davvero sicuro che sia in buona fede.
Ell

Quello che voglio dire è come distinguere tra input a = 1, b = 23e a = 12, b = 3. Non dovresti mettere 123STDIN in entrambi i casi?
Martin Ender,

1
Come ho detto, sembra funzionare (con 1 23e 12 3come input).
Ell

2
Ohhh, includi spazi nell'input. Sì, non mi sorprende che funzioni, in realtà.
Martin Ender,

5

64 61 caratteri

main(a,b){scanf("%d%d",&a,&b);for(a-=b;a/2;a/=2);putchar(a);}

Stampa i valori dei caratteri di -1, 0 e 1 per rispettivamente minore di, uguale o maggiore di.

Questa implementazione si basa sul comportamento definito per bessere di tipo inte per ingressi di fuori della gamma INT_MIN / 2di INT_MAX / 2. Sulle piattaforme in cui si avvolge l'overflow firmato, sia che si tratti del complemento 2s (praticamente tutti) o della grandezza del segno, fallirà per il 25% delle possibili coppie di valide int. È interessante notare (per me comunque), funzionerà correttamente su piattaforme in cui saturi di overflow firmato.


Questo non funzionerà se a-btrabocca.
Dennis,

Purtroppo è vero, ma non riuscivo a pensare a nessun modo agnostico di piattaforma per evitarlo senza operatori di confronto. La domanda non specifica un intervallo di input per i quali i risultati devono essere validi. Questa risposta è garantita dallo standard per funzionare per tutti gli input tra -(2^14)e 2^14 - 1su tutte le piattaforme conformi e probabilmente funzionerà per un intervallo sostanzialmente più ampio sulla maggior parte delle piattaforme. Tutte le altre risposte a questo punto fanno ipotesi sulla dimensione del tipo, sulle dimensioni relative dei tipi o sulla rappresentazione.
Laindir,

La domanda dice che due numeri interi con segno come input , quindi direi che deve funzionare per tutte le coppie. main(a,b)è già un comportamento indefinito, quindi nessuna delle risposte è garantita per funzionare. Non importa la portabilità.
Dennis,

Hai assolutamente ragione riguardo al comportamento indefinito, quindi la mia implementazione in realtà non garantisce nulla dallo standard. Aggiungerò una nota che indica quali sono i suoi limiti.
Laindir,

3

66 102 byte

main(a,b,c,d,e){scanf("%d %d",&a,&b);e=1<<31;c=a&e;d=b&e;putchar(a-b?c&~d?48:d&~c?49:a-b&e?48:49:50);}

Legge i numeri interi da STDIN e stampa 0(a <b), 1(a> b) o 2(a == b).

Modifica: ora dovrebbe funzionare anche per differenze troppo grandi per adattarsi a un numero intero a 32 bit. Sono sicuro che il ternario annidato può essere abbreviato con un po 'più di magia.


Correggimi se sbaglio, ma vedo un <0 nel tuo ternario interno.
overactor

@overactor fixed
Martin Ender

3

52 byte

Purtroppo questo funziona solo per numeri interi positivi, ma ho pensato che il concetto di usare operatori puramente aritmetici fosse interessante:

main(a,b){scanf("%d%d",&a,&b);putchar(b%a/b-a%b/a);}

Uscite:

  • Codice ASCII 0xFF: a inferiore a b
  • Codice ASCII 0x00: a uguale a b
  • Codice ASCII 0x01: a maggiore di b

Se stai andando solo per numeri interi positivi, putchar(a/b-b/a)è molto più breve.
Dennis,

@Dennis che produce output diversi, ad esempio per (50,1) e (51,1). Ma sono stato in grado di accorciare un po 'però.
Trauma digitale

1
Sì, non pensavo bene ...
Dennis,

3

 59    54 caratteri

54 caratteri con un compilatore come gcc che non si oppone a main(x,y):

main(x,y){scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

59 caratteri altrimenti:

main(){int x,y;scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

Produzione:

  • Codice ASCII 0x00 se x <y
  • Codice ASCII 0xFF se x> y
  • Codice ASCII 0x01 se x == y

1
Posso assicurarti che main(x,y)funziona in gcc, quindi sentiti libero di eliminare quei 5 byte dal conteggio dei personaggi.
Martin Ender,

main (x, y) non funziona sul mio gcc. Forse è richiesta un'opzione del compilatore. Ma puoi sostituire main (x, y) con x; main (y).
Florian F,

2

66 byte

main(a,b){scanf("%d%d",&a,&b);putchar((0l+b-a>>63)-(0l+a-b>>63));}

Stampa il byte 0x00 if a == b, 0x01 if a < be 0xff if a > b.

Dato che il carattere ASCII non ASCII o non stampabile nel programma [my] e se qualcosa non è esplicitamente vietato nella domanda, è consentito , il carattere non stampabile nell'output dovrebbe essere completamente corretto.


La mia versione precedente non gestiva molto bene l'overflow. Funziona su x64 Linux, dove longè a 64 bit.
Dennis,

2

87 caratteri

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a+=c;b+=c;puts(a^b?(unsigned)a/b?">":"<":"=");}

Usando il trucco 2 ^ 31 per convertire in int senza segno

Trasmettere la divisione su unsigned per gestire il bit superiore come dati, non come segno

Usando ^ a XOR aeb, quando sono uguali, questo restituisce 0

Utilizzo dei condizionali nidificati (?) Per ottenere "<", ">" o "=" per alimentare put ()


1

71 byte

main(x,y,z){scanf("%d%d",&x,&y);putchar((z=x-y)?(z&(z>>31))?50:49:51);}

http://ideone.com/uvXm6c


Il tuo ideone ha delle parentesi z=x-ye sono abbastanza sicuro che siano necessarie. Puoi anche salvare due caratteri usando 49, 50` e 51direttamente, invece di aggiungere 48.
Martin Ender,

L'assegnazione ha una precedenza inferiore rispetto all'operatore ternario: en.cppreference.com/w/c/language/operator_precedence
Martin Ender

Nel codice sopra manca un punto e virgola e non riesce -2000000000 2000000000, così come qualsiasi altra combinazione di numeri interi che causano l'overflow nella sottrazione.
COTO

1

68 caratteri

int main(a,b){scanf("%d%d",&a,&b);putchar(a-b?((unsigned)a-b)>>31:2);}

Inserisce il carattere ASCII 1, 2 o 3 per rispettivamente minore di, maggiore o uguale.


1
Questo non funzionerà se a-btrabocca.
Dennis,

1

88 89 byte

main(a,b){scanf("%d%d",&a,&b);a+=1<<31;b+=1<<31;for(;a&&b;a--)b--;putchar(a?b?48:49:50);}

Questo inizia aggiungendo 1<<31( INT_MIN) a aeb, in modo che 0 ora corrisponda INT_MIN. Quindi esegue il loop e decrementa aeb ogni loop fino a quando uno è 0, quindi stampa 0, 1 o 2 a seconda che a, b o entrambi siano 0.

120 119 byte

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a^=c;b^=c;for(c~=c;!c;c/=2)if(a&c^b&c){putchar(a?48:49);return;}putchar(50);}

Non è la soluzione più breve com'è, ma potrebbe essere un po 'golfata da un golfista migliore di me. (O solo persone con più conoscenza della C di me)

L'idea è di mascherare ogni bit, partendo da quello sinistro e verificando la disuguaglianza. Il resto dovrebbe spiegarsi. Poiché i numeri negativi iniziano con un 1 bit, per prima cosa invertisco il primo bit con a^=1<<31.


Non posso testare le mie soluzioni per il momento, quindi sentiti libero di segnalare errori.
overactor

La prima soluzione ha un paio di problemi: 1. La ;)faccina felice dovrebbe essere una );faccina triste . 2. a&bverifica solo se ae bhanno bit in comune; hai bisogno &&.
Dennis,

@Dennis, hai ragione, grazie.
overactor

1

Penso che non proverò nemmeno a scrivere codice breve. Quello che cercherò di eseguire questo confronto in un modo portatile secondo le specifiche C99.

int a, b;   // Let's assume these are initialized
int sign_a = a ? ((a|7)^2)%2 + ((a|7)^3)%2 : 0;

L'operatore modulo conserva il segno, ma può anche produrre uno zero (incluso lo zero negativo), quindi ci assicuriamo di avere sia un valore pari che dispari da controllare (anche senza sapere se stiamo usando i complementi). Le operazioni aritmetiche possono traboccare, ma non lo faranno bit a bit, e assicurandoci che ci siano bit sia impostati che cancellati, evitiamo di convertire inavvertitamente il nostro numero in zero negativo o in un valore trap. Il fatto che siano necessarie due operazioni per farlo in modo strano non dovrebbe importare, perché la possibile rappresentazione della trap non causa un comportamento indefinito fino a quando non viene inserito in un valore. Se si esegue l'operazione con il bit 0 attivato, si ottiene esattamente un resto diverso da zero. Armati della conoscenza di entrambi i segni, possiamo decidere come procedere con il confronto.

char result="\0<<>=<>>\0"[4+3*sign_a+sign_b]
if (!result) {   // signs matching means subtraction won't overflow
  int diff=a-b;
  int sign_diff=diff ? (diff|7^2)%2 + (diff|7^3)%2 : 0;
  result = ">=<"[1-sign_diff];
}

Questo metodo può essere uno dei pochi che consente di estrarre il segno di uno zero intero negativo. Lo risolviamo controllando esplicitamente lo zero. Se stessimo giocando a golf sul serio, potremmo ovviamente consentire il confronto di due zeri per eseguire anche la sottrazione.


1

C 80 caratteri

a,b,c=1<<31;main(){scanf("%d%d",&a,&b);putchar(a^b?(a&c^b&c?a:a-b)&c?60:62:61);}

Stampa '<', '>' o '=', come dovrebbe.

C 63 caratteri

Un nuovo approccio:

a;main(b){scanf("%d%d",&a,&b);putchar(50+(0L+a-b>>42)+!(a-b));}

Stampa '1', '2' o '3'.


1

In 64 caratteri senza stdio.h

a,b;main(){scanf("%d%d",&a,&b);puts((a-b)>>31?"<":a^b?">":"=");}

stampa '>' se a> b, '<' se a <b, '=' se a == b int overflow è UB. Basta non traboccare.

// declare a and b as ints
a,b;

// defaults to int
main()
{
  scanf("%d%d",&a,&b);
   /*
    * (a-b)>>31 signbit of a-b
    * a^b a xor b -> 0 if they are equal
    */
  puts(((a-b)>>31) ? "<" : (a^b) ? ">" : "=");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.