2015-08-08 25 views
6

Sto tentando esercizio 2.1 di K & R.Come determinare a livello intero numero intero/min in C?

L'esercizio è così formulato:

Scrivi un programma per determinare gli intervalli di char, short, int, e le variabili lunghi, entrambi firmati e non firmati , stampando i valori appropriati dalle intestazioni standard e mediante calcolo diretto. Più difficile se li calcolhi: determina gli intervalli dei vari tipi a virgola mobile.

Stampa dei valori delle costanti nelle intestazioni standard è semplice, proprio come questo (solo numeri interi mostrato per esempio):

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

Tuttavia, voglio per determinare i limiti di programmazione.

Ho provato questo codice che sembra che dovrebbe funzionare, ma in realtà va in un ciclo infinito e si blocca lì:

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

Perché questo conficcato in un ciclo? Sembrerebbe che quando un intero trabocca salta da 2147483647 a -2147483648. Il valore incrementato è ovviamente più piccolo del valore precedente, quindi il ciclo dovrebbe terminare, ma non lo è.

+2

Questo funziona bene sul mio sistema. Immagino che il ciclo non si sia bloccato, ci è voluto molto tempo perché int_max nel tuo sistema è troppo grande. – Mureinik

+0

Aha! Hai ragione! Immagino che 2.147.483.647 incrementi siano sufficienti per completare alcuni cicli. –

+3

Se si blocca in un loop infinito (controllare l'assemblaggio per essere sicuri). Il compilatore può ottimizzare '(i_max + 1)> i_max' su true poiché l'overflow con segno non è definito. – FDinoff

risposta

7

Ok, stavo per scrivere un commento, ma faceva troppo lungo ...

È consentito utilizzare sizeof?

Se fosse vero, allora c'è un modo semplice per trovare il valore massimo per qualsiasi tipo:

Per esempio, troverò il valore massimo per un numero intero:

Definizione: INT_MAX = (1 << 31) - 1 per 32- bit integer (2^31 - 1)

La precedente definizione trabocca se usiamo interi calcolare int max, quindi, deve essere adattato correttamente:

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

E l'utilizzo sizeof:

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

Si può fare lo stesso per qualsiasi firmato/tipo unsigned semplicemente leggendo le regole per ogni tipo.

+1

Si noti che questo funziona solo per il complemento a due, ma [che non dovrebbe essere un problema] (http://stackoverflow.com/q/12276957/2718186) in questi giorni. – MicroVirus

+0

Ho provato la stessa cosa con l'int64 firmato; 'long long lmax = (1 << 63) - 1' ma ha lmax = -1. Qualche idea del perché? – stt106

1

Quindi in realtà non era rimanere bloccato in un ciclo infinito.

Il codice C è in genere così veloce che presumo sia rotto se non viene completato immediatamente.

Alla fine ha restituito la risposta corretta dopo averlo lasciato funzionare per circa 10 secondi. Risulta che per completare 2.47.483.647 incrementi richiede parecchi cicli.

Devo anche notare che ho compilato con cc -O0 per disabilitare le ottimizzazioni, quindi questo non era il problema.

una soluzione più veloce potrebbe essere qualcosa di simile:

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

Tuttavia, come troppo pieno firmato è un comportamento indefinito, probabilmente si tratta di una pessima idea per cercare mai di indovinare di programmazione in pratica. Meglio usare INT_MAX.

+2

Quindi eri così ansioso che non avresti potuto aspettare 10 secondi in primo luogo? Quanto tempo ti ci è voluto per pubblicare questa domanda? – Amit

+1

Vedere il mio commento sopra: il codice C di solito è così veloce che presumo sia rotto se non viene completato immediatamente. –

+1

'così veloce che presumo sia rotto se non si completa immediatamente '- dipende da cosa fa il codice. Inoltre, l'overflow non firmato è ben definito; solo l'overflow dell'intero con segno è UB. Onestamente, non vedo come questa sia una risposta alla tua domanda (considerando che la tua soluzione è in realtà UB). –

0

Supponendo processore un complemento a due, usare matematica senza segno:

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

Come è stato fatto notare qui in altre soluzioni, cercando di traboccare un numero intero in C è un comportamento indefinito, ma, almeno in questo caso, Penso che tu possa ottenere una risposta valida, anche da UB cosa:

Il caso è che se si incrementa un valore e si confronta il nuovo valore con l'ultimo, si ottiene sempre un valore maggiore, eccetto su un overflow (in questo caso si otterrà un valore inferiore o uguale - -Non hanno più valori maggiori, questo è il caso in un overflow) in modo da poter provare almeno:

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

Dopo questo ciclo, si avrà ottenuto il troppo pieno previsto, e old_i memorizzerà l'ultimo valido numero. Naturalmente, nel caso in cui si scende, si dovrà utilizzare questo frammento di codice:

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

Naturalmente, U.B. può anche significare l'arresto del programma (in questo caso dovrai mettere delle tracce, per ottenere almeno l'ultimo valore stampato)

A proposito, nei tempi antichi di K & R, gli interi erano 16 bit ampio, un valore facilmente accessibile con il conteggio (più facile di adesso, prova overflow a 64 bit overflow da 0 in su)

Problemi correlati