2015-08-08 4 views
6

Ich versuche Übung 2.1 von K & R.Wie programmiere ich ganzzahlig max/min in C?

Die Übung lautet wie folgt:

Schreiben Sie ein Programm, die Bereiche von char, short, int und long Variablen zu bestimmen, die beide mit und ohne Vorzeichen durch Drucken entsprechender Werte aus Standard-Headern und durch direkte Berechnung. Schwieriger, wenn Sie sie berechnen: Bestimmen Sie die Bereiche der verschiedenen Gleitkommatypen.

die Werte der Konstanten in den Standards Header Drucken ist einfach, genau wie diese (nur ganze Zahl zum Beispiel gezeigt):

printf("Integral Ranges (from constants)\n"); 
    printf("int max: %d\n", INT_MAX); 
    printf("int min: %d\n", INT_MIN); 
    printf("unsigned int max: %u\n", UINT_MAX); 

Allerdings möchte ich programmatisch die Grenzen bestimmen.

habe ich versucht, diesen Code, wie es sollte funktionieren scheint, aber es geht tatsächlich in eine Endlosschleife und wird dort stecken:

printf("Integral Ranges (determined programmatically)\n"); 

    int i_max = 0; 
    while ((i_max + 1) > i_max) { 
      ++i_max; 
    } 
    printf("int max: %d\n", i_max); 

Warum ist dies in einer Schleife stecken zu bleiben? Es scheint, dass, wenn eine Ganzzahl überläuft, sie von 2147483647 zu -2147483648 springt. Der inkrementierte Wert ist offensichtlich kleiner als der vorherige Wert, daher sollte die Schleife enden, tut dies aber nicht.

+2

Dies funktioniert gut auf meinem System. Ich schätze, dass die Schleife nicht hängen blieb, es dauerte nur sehr lange, da int_max in Ihrem System zu groß ist. – Mureinik

+0

Aha! Sie haben Recht! Ich nehme an, dass 2.147.483.647 Inkremente ziemlich viele Zyklen benötigen. –

+3

Wenn es in einer Endlosschleife steckenbleibt (überprüfen Sie die Baugruppe, um sicher zu gehen). Der Compiler darf "(i_max + 1)> i_max" auf "wahr" optimieren, da der vorzeichenbehaftete Überlauf nicht definiert ist. – FDinoff

Antwort

7

Ok, ich war etwa um einen Kommentar zu schreiben, aber es hat zu lange ...

Sind Sie sizeof verwenden?

Wenn das stimmt, dann gibt es einen einfachen Weg, um den Maximalwert für jede Art zu finden:

Zum Beispiel werde ich den maximalen Wert für eine ganze Zahl finden:

Definition: INT_MAX = (1 << 31) - 1 für 32- Bit-integer (2^31-1)

Die vorhergehende Definition überläuft, wenn wir ganze Zahlen verwenden int max zu berechnen, so hat es richtig angepasst werden:

INT_MAX = (1 << 31) - 1 
     = ((1 << 30) * 2) - 1 
     = ((1 << 30) - 1) * 2 + 2) - 1 
     = ((1 << 30) - 1) * 2) + 1 

Und mit sizeof:

INT_MAX = ((1 << (sizeof(int)*8 - 2) - 1) * 2) + 1 

Sie können das gleiche tun für jeden/ohne Vorzeichen Typen von nur für jede Art der Regeln zu lesen.

+1

Beachten Sie, dass dies nur für Zweierkomplement funktioniert, aber [das sollte kein Problem sein] (http://Stackoverflow.com/q/12276957/2718186) in diesen Tagen. – MicroVirus

+0

Versuchte das gleiche mit signed int64; 'lang lang lmax = (1 << 63) - 1 ', aber lmax = -1. Irgendeine Idee warum? – stt106

1

So ist es tatsächlich war nicht in einer Endlosschleife stecken.

C-Code ist in der Regel so schnell, dass ich davon ausgehe, es ist kaputt, wenn es nicht sofort abgeschlossen wird.

Es gab schließlich die richtige Antwort, nachdem ich es für etwa 10 Sekunden laufen ließ. Es stellt sich heraus, dass 2.147.483.647 Inkremente ziemlich viele Zyklen benötigen.

Ich sollte auch beachten, dass ich mit cc -O0 kompiliert, um Optimierungen zu deaktivieren, so war dies nicht das Problem.

Eine schnellere Lösung könnte etwa so aussehen:

int i_max = 0; 
    int step_size = 256; 
    while ((i_max + step_size) > i_max) { 
      i_max += step_size; 
    } 
    while ((i_max + 1) > i_max) { 
     ++i_max; 
    } 
    printf("int max: %d\n", i_max); 

jedoch als unterzeichneter Überlauf nicht definiertes Verhalten ist, wahrscheinlich ist es eine schreckliche Idee jemals versuchen programmatisch dies in der Praxis zu erraten. Besser, INT_MAX zu verwenden.

+2

Sie waren also besorgt, dass Sie nicht 10 Sekunden warten konnten? Wie viel Zeit haben Sie gebraucht, um diese Frage zu stellen? – Amit

+1

Siehe meinen Kommentar oben - C-Code ist in der Regel so schnell, dass ich davon ausgehe, dass es kaputt ist, wenn es nicht sofort abgeschlossen wird. –

+1

'so schnell, dass ich davon ausgehe, dass es kaputt ist, wenn es nicht sofort fertig wird '- es hängt davon ab, was der Code tut. Der vorzeichenlose Überlauf ist ebenfalls gut definiert. Nur vorzeichenbehafteter Ganzzahlüberlauf ist UB. Ehrlich gesagt, sehe ich nicht, wie dies eine Antwort auf Ihre Frage ist (in Anbetracht Ihrer Lösung ist eigentlich UB). –

0

eine Zweier-Komplement-Prozessor Unter der Annahme, verwenden unsigned Mathematik:

unsigned ... smax, smin; 
    smax = ((unsigned ...)0 - (unsigned ...)1)/(unsigned ...) 2; 
    smin = ~smax; 
0

Da es hier in anderen Lösungen hingewiesen wurde, eine ganze Zahl in C überzulaufen versucht, ist nicht definiertes Verhalten, aber zumindest in diesem Fall, Ich denke, du kannst eine gültige Antwort bekommen, sogar von der UB sache:

Der Fall ist, dass wenn Sie einen Wert erhöhen und den neuen Wert mit dem letzten vergleichen, erhalten Sie immer einen größeren Wert, außer bei einem Überlauf (in diesem Fall erhalten Sie einen Wert kleiner oder gleich - -Sie hat nicht mehr Werte größer, das ist der Fall in einem Überlauf) So kann man zumindest versuchen:

int i_old = 0, i = 0; 
while (++i > i_old) 
    i_old = i; 
printf("MAX_INT guess: %d\n", i_old); 

Nach dieser Schleife, haben Sie den erwarteten Überlauf bekommen, und old_i speichert die letzte gültig Nummer. Natürlich, falls nach unten Sie gehen, werden Sie diesen Code-Snippet verwenden müssen:

int i_old = 0, i = 0; 
while (--i < i_old) 
    i_old = i; 
printf("MIN_INT guess: %d\n", i_old); 

Natürlich U. B. kann sogar bedeuten, dass das Programm gestoppt wird (in diesem Fall müssen Sie Spuren setzen, um mindestens den letzten gedruckten Wert zu erhalten)

Übrigens, in den alten Zeiten von K & R waren ganze Zahlen 16bit breit, ein Wert leicht zugänglich durch Hochzählen (einfacher als jetzt, versuchen 64bit Ganzzahlen Überlauf von 0 bis)

Verwandte Themen