2015-12-16 10 views
5

Ho tentato KR esercizio 2.1: determinare il range delle variabili long mediante il calcolo diretto.Quando lo spostamento a sinistra non equivale a moltiplicare per 2

#include <stdio.h> 
#include <limits.h> 

int main() 
{ 
    unsigned short long_bits = sizeof(long) * CHAR_BIT; 
    printf("LONG_MAX = %ld\n", (1L << (long_bits - 1)) - 1); 
    printf("LONG_MIN = %ld\n", (-1) * (1L << (long_bits - 1))); 
    printf("ULONG_MAX (1) = %lu\n", (1UL << long_bits) - 1); // doesn't work 

    printf("ULONG_MAX (2) = %lu\n", 2*(1UL << (long_bits - 1)) - 1); // work 
    printf("\n"); 
} 
  • ULONG_MAX (1) = 0 è sbagliato perché lo spostamento di overflow sinistra suppongo.
  • ULONG_MAX (2) = 18446744073709551615 sembra corretto sostituendo l'ultimo spostamento sinistro con una moltiplicare per 2.

Così sembra che operatore di spostamento a sinistra soffre di troppo pieno, ma moltiplicazione non? Questo calcolo intermedio 2*(1UL << (long_bits - 1))promuove in un tipo diverso da long? Nella mia macchina, long e long long sono esattamente gli stessi (8 byte).


Edit: Come Lundin sottolineato, tutto il necessario per ULONG_MAX è printf("ULONG_MAX = %lu\n", ~0L);

Uso spostamento a sinistra in questo caso causato UB, e moltiplicare per 2 è potenzialmente UB, troppo (anche se risultato di cassa 2 look corretta).

+4

Come regola generale: l'aritmetica firmata soffre di (potenziale) overflow; aritmetica senza segno * non può * overflow (poiché eseguito modulo 2^N). – Jens

+0

Il caso 2 non è corretto neanche ... a causa di overflow come nel caso 1 – LPs

+0

@LPs - l'output del caso 2 sembra corretto. Questa è la mia domanda, l'overflow non sembra accadere in questo caso – artm

risposta

4

Il comportamento di spostamento a sinistra di un valore viene definito solo se la quantità di spostamento a sinistra è inferiore alla dimensione del tipo. Pertanto, 1UL << long_bits è un comportamento indefinito e qualsiasi cosa può accadere, compresi i demoni che volano fuori dal tuo naso.

Lascia che sia n il numero di bit nel tipo con cui stiamo lavorando. In pratica, a seconda della piattaforma, ci sono due comportamenti che si verificano in questo caso: O, qualsiasi spostamento a sinistra di n o più produce 0 (quando l'intero modello di bit viene spostato), o lo spostamento a sinistra è ridotto modulo n , quindi uno spostamento a sinistra di posti n si comporta come uno spostamento a sinistra nei posti 0, producendo 1UL << 0 o 1.

+0

Grazie. Sono d'accordo che il caso 1 non è definito. Il caso 2 è corretto? '2 * (1UL << (long_bits - 1))' appare più di quello che un tipo 'long' può contenere, quindi mi chiedo perché funzioni qui – artm

+1

@artm Anche questo caso non è definito. Perché non fai semplicemente '(unsigned long) -1L'? – fuz

Problemi correlati