Vergleichen Sie zwei Ganzzahlen in C oder C ++ ohne Vergleichsoperatoren

12

Produzieren Sie das kürzeste Programm, das zwei Ganzzahlen mit Vorzeichen als Eingabe (durch stdin oder als Argumente) verwendet und 3 verschiedene Ausgaben anzeigt, je nachdem, ob die erste Zahl (1) größer als, (2) kleiner als oder (3) gleich der zweiten ist Nummer.

Der Fang

Sie können keines der folgenden Elemente in Ihrem Programm verwenden:

  • Die Standardvergleichsoperatoren: <, >, <=, >=, ==,!= .
  • Jede Bibliothek Datei abgesehen von conio, stdiooderiostream .
  • Beliebiges Nicht-ASCII- oder nicht druckbares ASCII-Zeichen.

Der Gewinner

Das Programm mit der kürzesten Anzahl von Zeichen gewinnt.

Hain
quelle
Ich nehme an, Dinge wie das Verwenden abs ohne die Bibliotheksdatei einzuschließen (weil der Compiler es sowieso weiß) ist auch nicht erlaubt?
Martin Ender
1
@ Martinbüttner ja, das wäre eine richtige annahme. :)
Hain
5
Warum die Einschränkung auf C (++)? Wenn es darum geht, dass Antworten trotz der Unportabilität der Basistypen von C portabel sind, sollten Sie dies angeben. Wenn es sich um eine willkürliche Einschränkung handelt, sollten Sie sich darüber im Klaren sein, dass willkürliche Einschränkungen für eine Sprache auf dieser Site unpopulär sind.
Peter Taylor
8
@ PeterTaylor es ist Teil der Herausforderung. Es wäre ein ganz anderes Ballspiel, wenn die Frage sprachunabhängig wäre. Die Beschränkung auf C / C ++ ändert die Strategien, die bei der Lösung des Problems angewendet werden. Ich erkenne die Notwendigkeit, dass Fragen für die meisten Sprachen offen sind, um die Teilnahme von mehr Menschen zu fördern, aber in diesem speziellen Problem ist die Beschränkung auf C / C ++ und ihre spezifischen Operatoren und Methoden ein wesentlicher Bestandteil der Herausforderung.
Hain
1
@EvilTeach yes; wenn etwas in der frage nicht ausdrücklich verboten ist, dann ist es erlaubt.
Hain

Antworten:

2

53 Bytes

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

Nur das erste Zeichen der Ausgabe ist relevant. Die drei verschiedenen Ausgänge sind:

  1. '-' wenn b> a
  2. '0' wenn a == b
  3. jedes andere Zeichen, wenn a> b

Es funktioniert für den gesamten Eingabebereich von int auf allen Plattformen, auf denen sizeof (long)> sizeof (int) ist.

Bearbeiten: Es kostet ein zusätzliches Zeichen, wenn Fall 3 stattdessen ein '+' ausgibt:

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

Vielleicht fehlt mir etwas in den Regeln, aber ...

81 Bytes

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

Gibt 00if a > b, -10if a == bund -1-1if aus a < b.

COTO
quelle
So gebräuchlich diese Art von Code ist, C garantiert nicht, dass er funktioniert. long longkönnte mehr als 64 Bit sein, intkönnte so groß sein, dass Sie überlaufen könnten, das Ergebnis der Rechtsverschiebung negativer Werte wird durch die Implementierung definiert. Nahezu alle von C abgeleiteten Antworten weisen ähnliche Probleme auf.
Yann Vernier
1
@YannVernier: Verstanden. Ich vermute, eine 100% narrensichere Lösung wäre ein Monster, da das einzige, was wir sicher tun können (dh ohne zu verschieben oder zu überlaufen), ein bisschen herumzudrehen ist. Um dies sicher zu tun, müssten wir die Länge der Operanden mithilfe von bestimmen sizeof.
COTO
6

90 Bytes

Wenn wir verwenden können stdio, warum nicht die Formatierungsfunktionen verwenden, um einen Vergleich durchzuführen?

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

Setzt ASCII-kompatible Codierung und Little-Endianness voraus.

72 Bytes

Quotienten werden auf Null gerundet, aber Rechtsverschiebungen werden (in der Praxis) "abgerundet". Das ist ein totes Werbegeschenk.

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

65 79 Bytes

Eine weitere Unterscheidungseigenschaft von negativen Zahlen ist, dass sie ein negatives Modulo erzeugen. Dieser hängt überhaupt nicht von der Ganzzahldarstellung ab; es funktioniert sogar mit meinem 8-Bit-Toaster mit über 127 Bit! Oh, und da wir verwenden können conio, warum spart man nicht zwei Bytes mit putch? Nun, wenn ich nur meine Kopie von TurboC finden könnte ...

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

BEARBEITEN : Behandle große Unterschiede, vorausgesetzt sie long longsind größer als int.

Ell
quelle
Ich bin mir ziemlich sicher, dass Sie ein Trennzeichen zwischen den %ds in Ihrem brauchen scanf, um zwei ganze Zahlen eindeutig zu analysieren. Gute Idee!
Martin Ender
1
@Martin: Nun, es funktioniert mit GCC, aber ich bin mir nicht sicher, ob es echt ist.
Ell
Was ich meine ist, wie unterscheiden Sie zwischen Eingaben a = 1, b = 23und a = 12, b = 3. Würden Sie nicht brauchen , setzen 123auf STDIN in jedem Fall?
Martin Ender
1
Wie gesagt, es scheint zu funktionieren (mit 1 23und 12 3als Eingaben).
Ell
2
Ohhh, du fügst Leerzeichen in die Eingabe ein. Ja, ich bin nicht überrascht, dass das tatsächlich funktioniert.
Martin Ender
5

64 61 Zeichen

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

Gibt die Zeichenwerte -1, 0 und 1 für weniger als, gleich oder größer als aus.

Diese Implementierung stützt sich auf undefiniertes Verhalten, um bvom Typ zu sein intund Eingaben außerhalb des Bereichs INT_MIN / 2zu ermöglichen INT_MAX / 2. Auf Plattformen, auf denen ein vorzeichenbehafteter Überlauf auftritt, egal ob 2s-Komplement (im Grunde alle) oder Vorzeichengröße, schlägt dies für 25% der möglichen Paare von gültigen fehl int. Interessanterweise (für mich jedenfalls) funktioniert es auf Plattformen, auf denen signierte Überläufe gesättigt sind, korrekt.

Laindir
quelle
Dies funktioniert nicht, wenn es a-büberläuft.
Dennis
Leider stimmt das, aber ich könnte mir keinen plattformunabhängigen Weg vorstellen, um dies ohne Vergleichsoperatoren zu vermeiden. Die Frage gibt keinen Bereich von Eingaben an, für die Ergebnisse gültig sein müssen. Diese Antwort funktioniert nach dem Standard für alle Eingaben zwischen -(2^14)und 2^14 - 1auf allen kompatiblen Plattformen, und auf den meisten Plattformen wird sie wahrscheinlich für einen wesentlich größeren Bereich funktionieren. Bei allen anderen Antworten werden an dieser Stelle Annahmen über die Größe des Typs, die relative Größe des Typs oder die Darstellung getroffen.
Laindir
Die Frage besagt, dass zwei vorzeichenbehaftete Ganzzahlen als Eingabe verwendet werden. Ich würde also sagen, dass dies für alle Paare funktionieren muss. main(a,b)ist bereits undefiniertes Verhalten, daher funktioniert garantiert keine der Antworten. Keine Sorge, Portabilität.
Dennis
Sie haben absolut Recht, was das undefinierte Verhalten angeht. Meine Implementierung garantiert also nicht wirklich, dass es sich um einen Standard handelt. Ich werde einen Hinweis hinzufügen, in dem die Einschränkungen angegeben sind.
Laindir
3

66 102 Bytes

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);}

Liest die Ganzzahlen aus STDIN und gibt 0(a <b), 1(a> b) oder 2(a == b) aus.

Bearbeiten: Jetzt sollte es auch für Unterschiede funktionieren, die zu groß sind, um in eine 32-Bit-Ganzzahl zu passen. Ich bin mir sicher, dass verschachtelte Ternäre mit ein bisschen mehr Magie verkürzt werden können.

Martin Ender
quelle
Korrigieren Sie mich, wenn ich falsch liege, aber ich sehe eine <0 in Ihrem inneren Ternär.
Overactor
@overactor behoben
Martin Ender
3

52 Bytes

Leider funktioniert dies nur für positive ganze Zahlen, aber ich fand das Konzept der Verwendung rein arithmetischer Operatoren interessant:

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

Ausgänge:

  • ASCII-Code 0xFF: a kleiner als b
  • ASCII-Code 0x00: a gleich b
  • ASCII-Code 0x01: a größer als b
Digitales Trauma
quelle
Wenn Sie nur für positive ganze Zahlen gehen, putchar(a/b-b/a)ist viel kürzer.
Dennis
@Dennis, das unterschiedliche Ausgaben erzeugt, zum Beispiel für (50,1) und (51,1). Aber ich konnte ein bisschen verkürzen.
Digital Trauma
1
Ja, dachte nicht richtig ...
Dennis
3

 59    54 Zeichen

54 Zeichen mit einem Compiler wie gcc, der nichts ausmacht main(x,y):

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

59 Zeichen sonst:

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

Ausgabe:

  • ASCII-Code 0x00, wenn x <y
  • ASCII-Code 0xFF wenn x> y
  • ASCII-Code 0x01, wenn x == y
Todd Lehman
quelle
1
Ich kann Ihnen versichern, dass es main(x,y)in gcc funktioniert. Sie können also diese 5 Bytes aus Ihrer Zeichenanzahl entfernen.
Martin Ender
main (x, y) funktioniert auf meinem gcc nicht. Möglicherweise ist eine Compiler-Option erforderlich. Sie können jedoch main (x, y) durch x; main (y) ersetzen.
Florian F
2

66 Bytes

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

a == bGibt das Byte 0x00 if , 0x01 if a < bund 0xff if aus a > b.

Da Nicht-ASCII- oder nicht druckbare ASCII-Zeichen in [my] -Programmen und wenn etwas in der Frage nicht ausdrücklich verboten ist, ist es zulässig , dass nicht druckbare Zeichen in der Ausgabe vollständig in Ordnung sind.

Dennis
quelle
Meine Vorgängerversion hat den Überlauf nicht besonders gut bewältigt. Dies funktioniert unter x64 Linux mit long64-Bit.
Dennis
2

87 Zeichen

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

Verwenden Sie den 2 ^ 31-Trick, um in vorzeichenlose ints zu konvertieren

Umwandlung der Division in vorzeichenlos, um das obere Bit als Daten und nicht als Vorzeichen zu behandeln

Mit ^ zu XOR a und b, wenn sie gleich sind, wird 0 zurückgegeben

Verwenden verschachtelter Bedingungen (?), Um "<", ">" oder "=" für den Feed zu puts () zu erhalten

Pelle
quelle
1

71 Bytes

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

http://ideone.com/uvXm6c

Michael M.
quelle
Ihre Idee hat Klammern z=x-yund ich bin mir ziemlich sicher, dass sie notwendig sind. Sie können auch zwei Zeichen speichern, indem Sie 49, 50 und 51direkt verwenden, anstatt sie hinzuzufügen 48.
Martin Ender
Die Zuweisung hat eine niedrigere Priorität als der ternäre Operator: en.cppreference.com/w/c/language/operator_precedence
Martin Ender
In Ihrem obigen Code fehlt ein Semikolon, und es schlägt fehl -2000000000 2000000000, sowie für jede andere Kombination von Ganzzahlen, die einen Überlauf bei der Subtraktion verursachen.
COTO
1

68 Zeichen

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

Setzt ASCII-Zeichen 1, 2 oder 3 für kleiner als, größer als oder gleich.

CompuChip
quelle
1
Dies funktioniert nicht, wenn es a-büberläuft.
Dennis
1

88 89 Bytes

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);}

Dies beginnt mit dem Hinzufügen von 1<<31( INT_MIN) zu a und b, sodass 0 jetzt entsprichtINT_MIN . Dann schleifen und dekrementieren Sie a und b bei jeder Schleife, bis entweder 0 ist, und geben dann 0, 1 oder 2 aus, je nachdem, ob a, b oder beide 0 sind.

120 119 Bytes

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);}

Es ist nicht die kürzeste Lösung, könnte aber von einem besseren Golfer als mir ein bisschen heruntergolfen werden. (Oder einfach Leute mit mehr C-Kenntnissen als ich)

Die Idee ist, jedes Bit zu maskieren, beginnend mit dem linken und auf Ungleichheit zu prüfen. Der Rest sollte sich erklären. Da negative Zahlen mit einem 1-Bit beginnen, invertiere ich zuerst das erste Bit mit a^=1<<31.

Überakteur
quelle
Ich kann meine Lösungen derzeit nicht testen. Sie können also auf Fehler hinweisen.
Overactor
Die erste Lösung hat ein paar Probleme: 1. Der fröhliche ;)Smiley sollte ein trauriger );Smiley sein. 2. a&bprüft nur, ob aund welche bBits gemeinsam sind; du brauchst &&.
Dennis
@ Tennis, du hast recht, danke.
Overactor
1

Ich glaube, ich werde nicht einmal versuchen, Kurzcode zu schreiben. Ich werde versuchen, diesen Vergleich so durchzuführen, dass er gemäß der C99-Spezifikation portabel ist.

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

Der Modulo-Operator behält das Vorzeichen bei, kann aber durchaus eine Null (einschließlich einer negativen Null) erzeugen, sodass wir sicherstellen, dass sowohl ein ungerader als auch ein gerader Wert für die Überprüfung verfügbar sind (auch ohne zu wissen, ob wir ein Einsen-Komplement verwenden). Arithmetische Operationen können überlaufen, werden jedoch nicht bitweise ausgeführt. Indem sichergestellt wird, dass sowohl gesetzte als auch gelöschte Bits vorhanden sind, vermeiden wir, dass unsere Zahl versehentlich in eine negative Null oder einen Trap-Wert konvertiert wird. Die Tatsache, dass zwei Operationen erforderlich sind, um dies seltsam zu tun, sollte keine Rolle spielen, da die mögliche Trap-Darstellung kein undefiniertes Verhalten hervorruft, bis ein Wert eingegeben wird. Wenn Sie die Operation mit umgeschaltetem Bit 0 ausführen, erhalten Sie genau einen Rest ungleich Null. Mit der Kenntnis beider Zeichen können wir entscheiden, wie mit dem Vergleich verfahren werden soll.

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];
}

Diese Methode kann eine von wenigen sein, die das Extrahieren des Vorzeichens einer ganzzahligen negativen Null ermöglichen. Wir lösen das, indem wir explizit auf Null prüfen. Wenn wir wirklich Golf spielen würden, könnten wir natürlich den Vergleich von zwei Nullen zulassen, um auch die Subtraktion durchzuführen.

Yann Vernier
quelle
1

C 80 Zeichen

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);}

Es gibt '<', '>' oder '=' aus, wie es sollte.

C 63 Zeichen

Ein neuer Ansatz:

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

Druckt '1', '2' oder '3'.

Florian F
quelle
1

In 64 Zeichen ohne stdio.h

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

Gibt '>' aus, wenn a> b, '<', wenn a <b, '=', wenn a == b int overflow UB ist. Nur nicht überlaufen.

// 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) ? ">" : "=");
}
ViralTaco_
quelle