2010-05-05 18 views
7

Aby być na tej samej stronie, załóżmy, sizeof (int) = 4 i sizeof (long) = 8.Efektywne przesunięcie tablicy int?

Biorąc pod uwagę tablicę liczb całkowitych, jaka byłaby skuteczna metoda logicznego przesunięcia tablicy w lewo lub w prawo?

Zastanawiam się nad zmienną pomocniczą, taką jak długa, która wyliczy bitshift dla pierwszej pary elementów (indeks 0 i 1) i ustawi pierwszy element (0). Kontynuując w ten sposób bitshift dla elementów (indeks 1 i 2) będzie komputerem, a następnie zostanie ustawiony indeks 1.

Myślę, że jest to dość skuteczna metoda, ale są wady. Nie mogę przenieść więcej niż 32 bitów. Myślę, że używanie wielu zmiennych pomocniczych działałoby, ale wyobrażam sobie rekurencję gdzieś wzdłuż linii.

+0

@nn - to trochę niejasne, co tu robisz. Co chcesz zrobić z dowolnymi danymi, które są przesunięte i utracone? Czy chcesz logicznie przesuwać lub przesuwać arytmetycznie dane? A może po prostu czytasz losowo wybrane bitowe bity danych? Na przykład odczytać 4-bajtowe int z bitu pozycji 27 do 59 z 100-bajtowego strumienia danych binarnych? – ChrisBD

+0

@ChrisBD: Przepraszam, dobre pytanie. Logiczne przesunięcie. Właściwie operuję dużymi liczbami całkowitymi reprezentowanymi jako tablica ints, gdzie każdy int odpowiada cyfrze w podstawie 2^(sizeof (int) * 8) = 2^32. – snap

+0

Szukałem kilku czarodziejskich odniesień i nie widziałem żadnej sztuczki do tego, myślę, że oczywisty sposób jest jedyny sposób: -/ – fortran

Odpowiedz

1

Spójrz na BigInteger implementation in Java, który wewnętrznie przechowuje dane jako tablicę bajtów. W szczególności możesz sprawdzić function leftShift(). Składnia jest taka sama jak w C, więc napisanie pary takich funcji nie byłoby zbyt trudne. Weź też pod uwagę, że jeśli chodzi o przenoszenie bitów, możesz skorzystać z doradztwa nieutrwalonych typów w C. Oznacza to, że w Javie bezpiecznie przenosić dane bez naruszania znaku, zwykle potrzebujesz większych typów do przechowywania danych (np. Int do przesunięcia krótki, długi, aby przesunąć int, ...)

8

Nie ma potrzeby używania long jako pośrednika. Jeśli przesuwasz się w lewo, zacznij od najwyższego rzędu int, przesuwając prawy początek na najniższy. Dodaj element przenoszący z sąsiedniego elementu, zanim go zmodyfikujesz.

void ShiftLeftByOne(int * arr, int len) 
{ 
    int i; 
    for (i = 0; i < len - 1; ++i) 
    { 
     arr[i] = (arr[i] << 1) | ((arr[i+1] >> 31) & 1); 
    } 
    arr[len-1] = arr[len-1] << 1; 
} 

Ta technika może zostać przedłużona, aby wykonać przesunięcie o więcej niż 1 bit. Jeśli robisz więcej niż 32 bity, bierzesz liczbę bitów mod 32 i przesuwasz ją o, przesuwając wynik dalej wzdłuż tablicy. Na przykład, w celu przesunięcia w lewo o 33 bitów, kod wygląda prawie takie same:

void ShiftLeftBy33(int * arr, int len) 
{ 
    int i; 
    for (i = 0; i < len - 2; ++i) 
    { 
     arr[i] = (arr[i+1] << 1) | ((arr[i+2] >> 31) & 1); 
    } 
    arr[len-2] = arr[len-1] << 1; 
    arr[len-1] = 0; 
} 
+0

Ah, więc robisz modulo 32 w indeksach tablicy. Sprytna sztuczka. – snap

+1

Czy możesz wyjaśnić, od czego zacząć przenoszenie? Mówisz, że zaczynasz przesuwać się w lewo, używając najwyższego rzędu int. Jednak w Twoim fragmencie kodu wydaje się, że przesuwasz się od najniższego rzędu int. Również na przesunięciu o jeden, co wskazuje (& 1)? Dzięki. – snap

+0

Przepraszam, poszedłem na ciebie z wielkim endianinem. Masz rację, kolejność w szyku jest cofana. Opcja & 1 maskuje pojedynczy bit; aby otrzymać 2 bity, a 3, 4 bity to & 0xf, 7 bitów to & 0x3f itd. –

1

dla każdego innego, to jest więcej generycznego z Mark Ransom's answer powyżej dla liczby bitów, zaś każdy rodzaj tablicy :

/* This function shifts an array of byte of size len by shft number of 
bits to the left. Assumes array is big endian. */ 

#define ARR_TYPE uint8_t 

void ShiftLeft(ARR_TYPE * arr_out, ARR_TYPE * arr_in, int arr_len, int shft) 
{ 
    const int int_n_bits = sizeof(ARR_TYPE) * 8; 
    int msb_shifts = shft % int_n_bits; 
    int lsb_shifts = int_n_bits - msb_shifts; 
    int byte_shft = shft/int_n_bits; 
    int last_byt = arr_len - byte_shft - 1; 
    for (int i = 0; i < arr_len; i++){ 
     if (i <= last_byt){ 
      int msb_idx = i + byte_shft; 
      arr_out[i] = arr_in[msb_idx] << msb_shifts; 
      if (i != last_byt) 
       arr_out[i] |= arr_in[msb_idx + 1] >> lsb_shifts; 
     } 
     else arr_out[i] = 0; 
    } 
} 
Powiązane problemy