বি তে বিপরীত (এমএসবি-> এলএসবি থেকে এলএসবি-> এমএসবি) এর দক্ষ অ্যালগরিদম


243

নিম্নলিখিত অর্জনের জন্য সবচেয়ে কার্যকর অ্যালগরিদম কী:

0010 0000 => 0000 0100

রূপান্তরটি এমএসবি-> এলএসবি থেকে এলএসবি-> এমএসবিতে। সমস্ত বিট বিপরীত করা আবশ্যক; যে, এই না endianness-সোয়াপিং।


1
আমি মনে করি উপযুক্ত নামটি কিছুটা অপারেশন।
ক্রেডেন্স

5
আমি মনে করি আপনি বিবর্তন বলতে চেয়েছিলেন, আবর্তন নয়।
জুলিয়ানো

2
বেশিরভাগ এআরএম প্রসেসরের এটির জন্য বিল্ট-ইন অপারেশন রয়েছে। এআরএম কর্টেক্স-এম0 না এবং আমি খুঁজে পেয়েছি বিটগুলিকে অদলবদল করতে প্রতি বাইট টেবিল ব্যবহার করা দ্রুততম পদ্ধতির।
স্টার ব্লু

2
শন ইরন অ্যান্ডারসনের বিট টুইডলিং হ্যাকসও দেখুন
jww

2
দয়া করে "সেরা" সংজ্ঞা দিন
লি টেলর

উত্তর:


497

দ্রষ্টব্য : নীচের সমস্ত অ্যালগরিদম সিতে রয়েছে তবে আপনার পছন্দের ভাষার জন্য পোর্টেবল হওয়া উচিত (যখন তারা তত দ্রুত না হন তখন কেবল আমার দিকে তাকাবেন না :)

বিকল্প

নিম্ন মেমরি (32 বিট int, 32 বিট মেশিনের) (থেকে এখানে ):

unsigned int
reverse(register unsigned int x)
{
    x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
    return((x >> 16) | (x << 16));

}

বিখ্যাত বিট টুইডলিং হ্যাক্স পৃষ্ঠা থেকে :

দ্রুততম (দেখার সারণী) :

static const unsigned char BitReverseTable256[] = 
{
  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};

unsigned int v; // reverse 32-bit value, 8 bits at time
unsigned int c; // c will get v reversed

// Option 1:
c = (BitReverseTable256[v & 0xff] << 24) | 
    (BitReverseTable256[(v >> 8) & 0xff] << 16) | 
    (BitReverseTable256[(v >> 16) & 0xff] << 8) |
    (BitReverseTable256[(v >> 24) & 0xff]);

// Option 2:
unsigned char * p = (unsigned char *) &v;
unsigned char * q = (unsigned char *) &c;
q[3] = BitReverseTable256[p[0]]; 
q[2] = BitReverseTable256[p[1]]; 
q[1] = BitReverseTable256[p[2]]; 
q[0] = BitReverseTable256[p[3]];

আপনি এই ধারণাটি -৪-বিট-এ প্রসারিত করতে পারেন int, বা গতির জন্য মেমোরি ট্রেড করতে পারেন (আপনার এল 1 ডেটা ক্যাশে যথেষ্ট বড় বলে ধরে নেওয়া যায়) এবং K৪ কে-এন্ট্রি দেখার সারণীর সাহায্যে একসাথে ১ 16 বিট বিপরীত করতে পারেন।


অন্যান্য

সহজ

unsigned int v;     // input bits to be reversed
unsigned int r = v & 1; // r will be reversed bits of v; first get LSB of v
int s = sizeof(v) * CHAR_BIT - 1; // extra shift needed at end

for (v >>= 1; v; v >>= 1)
{   
  r <<= 1;
  r |= v & 1;
  s--;
}
r <<= s; // shift when v's highest bits are zero

দ্রুত (32-বিট প্রসেসর)

unsigned char b = x;
b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; 

দ্রুত (-৪-বিট প্রসেসর)

unsigned char b; // reverse this (8-bit) byte
b = (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;

আপনি যদি 32-বিটে এটি করতে চান intতবে প্রতিটি বাইটের বিটগুলি বিপরীত করুন এবং বাইটগুলির ক্রমটি বিপরীত করুন। এটাই:

unsigned int toReverse;
unsigned int reversed;
unsigned char inByte0 = (toReverse & 0xFF);
unsigned char inByte1 = (toReverse & 0xFF00) >> 8;
unsigned char inByte2 = (toReverse & 0xFF0000) >> 16;
unsigned char inByte3 = (toReverse & 0xFF000000) >> 24;
reversed = (reverseBits(inByte0) << 24) | (reverseBits(inByte1) << 16) | (reverseBits(inByte2) << 8) | (reverseBits(inByte3);

ফলাফল

আমি দুটি সর্বাধিক প্রতিশ্রুতিবদ্ধ সমাধান, চেহারা সারণী এবং বিটওয়াইস-এন্ড (প্রথমটি) bench পরীক্ষা মেশিনটি ডিডিআর 2-800 এর ল্যাপটপ ডাব্লু / 4 জিবি এবং একটি কোর 2 ডুও টি 7500 @ 2.4GHz, 4MB এল 2 ক্যাশে; YMMV। আমি 64-বিট লিনাক্সে জিসিসি 4.3.2 ব্যবহার করেছি । ওপেনএমপি (এবং জিসিসি বাইন্ডিং) উচ্চ-রেজোলিউশন টাইমারগুলির জন্য ব্যবহৃত হয়েছিল।

reverse.c

#include <stdlib.h>
#include <stdio.h>
#include <omp.h>

unsigned int
reverse(register unsigned int x)
{
    x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
    return((x >> 16) | (x << 16));

}

int main()
{
    unsigned int *ints = malloc(100000000*sizeof(unsigned int));
    unsigned int *ints2 = malloc(100000000*sizeof(unsigned int));
    for(unsigned int i = 0; i < 100000000; i++)
      ints[i] = rand();

    unsigned int *inptr = ints;
    unsigned int *outptr = ints2;
    unsigned int *endptr = ints + 100000000;
    // Starting the time measurement
    double start = omp_get_wtime();
    // Computations to be measured
    while(inptr != endptr)
    {
      (*outptr) = reverse(*inptr);
      inptr++;
      outptr++;
    }
    // Measuring the elapsed time
    double end = omp_get_wtime();
    // Time calculation (in seconds)
    printf("Time: %f seconds\n", end-start);

    free(ints);
    free(ints2);

    return 0;
}

reverse_lookup.c

#include <stdlib.h>
#include <stdio.h>
#include <omp.h>

static const unsigned char BitReverseTable256[] = 
{
  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};

int main()
{
    unsigned int *ints = malloc(100000000*sizeof(unsigned int));
    unsigned int *ints2 = malloc(100000000*sizeof(unsigned int));
    for(unsigned int i = 0; i < 100000000; i++)
      ints[i] = rand();

    unsigned int *inptr = ints;
    unsigned int *outptr = ints2;
    unsigned int *endptr = ints + 100000000;
    // Starting the time measurement
    double start = omp_get_wtime();
    // Computations to be measured
    while(inptr != endptr)
    {
    unsigned int in = *inptr;  

    // Option 1:
    //*outptr = (BitReverseTable256[in & 0xff] << 24) | 
    //    (BitReverseTable256[(in >> 8) & 0xff] << 16) | 
    //    (BitReverseTable256[(in >> 16) & 0xff] << 8) |
    //    (BitReverseTable256[(in >> 24) & 0xff]);

    // Option 2:
    unsigned char * p = (unsigned char *) &(*inptr);
    unsigned char * q = (unsigned char *) &(*outptr);
    q[3] = BitReverseTable256[p[0]]; 
    q[2] = BitReverseTable256[p[1]]; 
    q[1] = BitReverseTable256[p[2]]; 
    q[0] = BitReverseTable256[p[3]];

      inptr++;
      outptr++;
    }
    // Measuring the elapsed time
    double end = omp_get_wtime();
    // Time calculation (in seconds)
    printf("Time: %f seconds\n", end-start);

    free(ints);
    free(ints2);

    return 0;
}

আমি উভয় পদ্ধতির বিভিন্ন বিভিন্ন অপ্টিমাইজেশনে চেষ্টা করেছি, প্রতিটি স্তরে 3 টি ট্রায়াল চালিয়েছি এবং প্রতিটি বিচার 100 মিলিয়ন এলোমেলোভাবে বিপরীত হয়েছে unsigned ints। সারণী বিকল্পের জন্য, আমি বিটওয়াইস হ্যাক্স পৃষ্ঠায় প্রদত্ত দুটি স্কিম (বিকল্প 1 এবং 2) চেষ্টা করেছিলাম। ফলাফলগুলি নীচে দেখানো হয়েছে।

বিটওয়াইস এবং

mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -o reverse reverse.c
mrj10@mjlap:~/code$ ./reverse
Time: 2.000593 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 1.938893 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 1.936365 seconds
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O2 -o reverse reverse.c
mrj10@mjlap:~/code$ ./reverse
Time: 0.942709 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 0.991104 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 0.947203 seconds
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O3 -o reverse reverse.c
mrj10@mjlap:~/code$ ./reverse
Time: 0.922639 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 0.892372 seconds
mrj10@mjlap:~/code$ ./reverse
Time: 0.891688 seconds

সারণী সারণী (বিকল্প 1)

mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.201127 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.196129 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.235972 seconds              
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O2 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.633042 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.655880 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.633390 seconds              
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O3 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.652322 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.631739 seconds              
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 0.652431 seconds  

সারণী সারণী (বিকল্প 2)

mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.671537 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.688173 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.664662 seconds
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O2 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.049851 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.048403 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.085086 seconds
mrj10@mjlap:~/code$ gcc -fopenmp -std=c99 -O3 -o reverse_lookup reverse_lookup.c
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.082223 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.053431 seconds
mrj10@mjlap:~/code$ ./reverse_lookup
Time: 1.081224 seconds

উপসংহার

বিকল্প 1 সহ সন্ধানের টেবিলটি ব্যবহার করুনআপনি যদি পারফরম্যান্সের বিষয়ে উদ্বিগ্ন হন তবে (বাইট অ্যাড্রেসিং অবাক করা আশ্চর্যজনক নয়) সহ সন্ধানের । আপনার যদি আপনার সিস্টেমের বাইরে থাকা মেমরির প্রতিটি শেষ বাইট চেপে ধরার প্রয়োজন হয় (এবং আপনি যদি কিছুটা বিপরীতের পারফরম্যান্সের বিষয়ে যত্নশীল হন), বিটওয়াইস-ও অ্যাড্রোম এর অনুকূলিত সংস্করণগুলি খুব জঞ্জাল নয়।

বিচারকার্য স্থগিত রাখার আদেশ

হ্যাঁ, আমি জানি বেঞ্চমার্ক কোডটি একটি সম্পূর্ণ হ্যাক। এটি কীভাবে উন্নত করা যায় সে সম্পর্কে পরামর্শগুলি স্বাগত হওয়ার চেয়েও বেশি। আমি যে বিষয়গুলি সম্পর্কে জানি:

  • আইসিসিতে আমার অ্যাক্সেস নেই। এটি দ্রুত হতে পারে (আপনি যদি এটি পরীক্ষা করে দেখতে পারেন তবে একটি মন্তব্যে প্রতিক্রিয়া জানান)।
  • একটি 64 কে দেখার টেবিলটি বড় এল 1 ডি সহ কিছু আধুনিক মাইক্রোর্কিটেকচারগুলিতে ভাল করতে পারে।
  • -মিটিউন = নেটিভ -O2 / -O3 এর জন্য কাজ করে না ( ldকিছু উন্মাদ প্রতীক পুনরায় সংজ্ঞা ত্রুটির সাথে মিশে গেছে ), তাই আমি বিশ্বাস করি না যে জেনারেট কোডটি আমার মাইক্রোআরকিটেকচারের জন্য সুর করা হয়েছে।
  • এসএসই এর সাথে কিছুটা দ্রুত করার উপায় আছে। আমি কীভাবে জানি না, তবে দ্রুত প্রতিলিপি দিয়ে, কিছুটা বিছিন্নভাবে এবং, এবং সুইজলিং নির্দেশাবলীর সাথে সেখানে কিছু পাওয়া যায়।
  • আমি বিপজ্জনক হতে পারে শুধুমাত্র x86 সমাবেশ জানি; বিকল্পটি 1 এর জন্য জিওসিসি কোডটি -O3 এ উত্পন্ন হয়েছে, যাতে আমার চেয়ে আরও জ্ঞাতযোগ্য কেউ এটি পরীক্ষা করে দেখতে পারেন:

32-বিট

.L3:
movl    (%r12,%rsi), %ecx
movzbl  %cl, %eax
movzbl  BitReverseTable256(%rax), %edx
movl    %ecx, %eax
shrl    $24, %eax
mov     %eax, %eax
movzbl  BitReverseTable256(%rax), %eax
sall    $24, %edx
orl     %eax, %edx
movzbl  %ch, %eax
shrl    $16, %ecx
movzbl  BitReverseTable256(%rax), %eax
movzbl  %cl, %ecx
sall    $16, %eax
orl     %eax, %edx
movzbl  BitReverseTable256(%rcx), %eax
sall    $8, %eax
orl     %eax, %edx
movl    %edx, (%r13,%rsi)
addq    $4, %rsi
cmpq    $400000000, %rsi
jne     .L3

সম্পাদনা: uint64_tআমার মেশিনে প্রকারের পারফরম্যান্সের কোনও উত্সাহ রয়েছে কিনা তা দেখার জন্য আমিও চেষ্টা করেছি। পারফরম্যান্সটি 32-বিটের চেয়ে প্রায় 10% দ্রুত ছিল এবং আপনি intএকবারে দুটি 32-বিট প্রকারের বিটগুলি বিপরীত করতে কেবল 64-বিট প্রকারগুলি ব্যবহার করছেন কিনা, বা আপনি বাস্তবে অর্ধেকের মধ্যে বিটগুলি বিপরীত করছেন কিনা 64- বিট মান। অ্যাসেম্বলি কোডটি নীচে দেখানো হয়েছে (পূর্বের ক্ষেত্রে, intএকবারে দুটি 32-বিট ধরণের বিট বিপরীত করে ):

.L3:
movq    (%r12,%rsi), %rdx
movq    %rdx, %rax
shrq    $24, %rax
andl    $255, %eax
movzbl  BitReverseTable256(%rax), %ecx
movzbq  %dl,%rax
movzbl  BitReverseTable256(%rax), %eax
salq    $24, %rax
orq     %rax, %rcx
movq    %rdx, %rax
shrq    $56, %rax
movzbl  BitReverseTable256(%rax), %eax
salq    $32, %rax
orq     %rax, %rcx
movzbl  %dh, %eax
shrq    $16, %rdx
movzbl  BitReverseTable256(%rax), %eax
salq    $16, %rax
orq     %rax, %rcx
movzbq  %dl,%rax
shrq    $16, %rdx
movzbl  BitReverseTable256(%rax), %eax
salq    $8, %rax
orq     %rax, %rcx
movzbq  %dl,%rax
shrq    $8, %rdx
movzbl  BitReverseTable256(%rax), %eax
salq    $56, %rax
orq     %rax, %rcx
movzbq  %dl,%rax
shrq    $8, %rdx
movzbl  BitReverseTable256(%rax), %eax
andl    $255, %edx
salq    $48, %rax
orq     %rax, %rcx
movzbl  BitReverseTable256(%rdx), %eax
salq    $40, %rax
orq     %rax, %rcx
movq    %rcx, (%r13,%rsi)
addq    $8, %rsi
cmpq    $400000000, %rsi
jne     .L3

2
অতিরিক্ত বিস্তারিত এবং পুঙ্খানুপুঙ্খ পোস্টের জন্য -1। ঞ / ট। +1 টি।
এমপেন

8
এটি একটি আকর্ষণীয় অনুশীলন ছিল, যদি তা পরিপূর্ণ হয় না। যদি অন্য কিছু না হয় তবে আমি আশা করি যে প্রক্রিয়াটি এমন কারও পক্ষে গঠনমূলক, যিনি আরও কিছু গুণযুক্ত কিছু বেনমার্ক করতে চাইতে পারেন :)
ম্যাট জে

5
আমার ... ঈশ্বর! আমি মনে করি আমি খুঁজে পেয়েছি ... যা খুব ভাল হতে পারে ... একজন সত্য স্পেসিমান। আমাকে আমার নথিগুলির সাথে পরামর্শ করতে হবে, এবং আরও গবেষণা করতে হবে, তবে কিছু আমাকে (Godশ্বর, আমাকে সাহায্য করুন) বলে, এটি স্ট্যাক ওভারফ্লো এখনও পর্যন্ত সবচেয়ে বড়, সবচেয়ে পুঙ্খানুপুঙ্খ এবং দরকারী উত্তর answer এমনকি জন স্কিটিও হতবাক ও মুগ্ধ!
zeboidlund

3
মনে রাখবেন যে মাইক্রোবেঞ্চমার্কিংয়ের একটি বিশেষ ত্রুটি (অন্য অনেকের তালিকার মধ্যে একটি) এটি কৃত্রিমভাবে দেখার জন্য সারণী ভিত্তিক সমাধানগুলি সমর্থন করে। যেহেতু বেঞ্চমার্কটি একটি লুপের মধ্যে একটি ক্রিয়াকলাপ পুনরাবৃত্তি করছে, এটি প্রায়শই দেখতে পাবেন যে কেবলমাত্র L1- এ ফিট করে এমন একটি লুকিং টেবিল ব্যবহার করা সবচেয়ে দ্রুত, কারণ কোনও ক্যাশে চাপ না থাকায় সবকিছুই প্রতিবার এল 1 তে আঘাত হানবে। প্রকৃত ব্যবহারের ক্ষেত্রে, অপারেশনটি সাধারণত অন্যান্য ক্রিয়াকলাপগুলির সাথে আন্তঃবিবাহিত হবে যা কিছু ক্যাশের চাপ সৃষ্টি করে। র‌্যামে মিস করা স্বাভাবিকের চেয়ে 10 বা 100 গুণ বেশি সময় নিতে পারে তবে এটি মানদণ্ডে উপেক্ষা করা হয়।
BeeOnRope

2
ফলশ্রুতিটি হ'ল যদি দুটি সমাধান খুব কাছাকাছি থাকে তবে আমি প্রায়শই নন-লুট সমাধান (বা আরও ছোট এলটিউটের সাথে একটি) বেছে নেব কারণ একটি এলইউটি-র আসল ওয়ার্ল্ড ইফেক্টটি মারাত্মক হতে পারে। আরও ভাল হ'ল "সিটুতে" প্রতিটি সমাধান বেনমার্ক করা - যেখানে এটি বাস্তবে বাস্তবতর ইনপুট সহ বৃহত্তর প্রয়োগে ব্যবহৃত হয়। অবশ্যই, আমাদের কাছে এর জন্য সর্বদা সময় নেই এবং আমরা সবসময় জানি না যে বাস্তববাদী ইনপুট কী।
BeeOnRope

80

এই থ্রেডটি আমার দৃষ্টি আকর্ষণ করেছে যেহেতু এটি একটি সাধারণ সমস্যা নিয়ে কাজ করে যা এমনকি একটি আধুনিক সিপিইউয়ের জন্য প্রচুর পরিশ্রমের প্রয়োজন (সিপিইউ চক্র)। এবং একদিন আমি একই ¤ #% "#" সমস্যা নিয়ে সেখানে দাঁড়িয়েছি। আমাকে কয়েক মিলিয়ন বাইট ফিলিপ করতে হয়েছিল। তবে আমি জানি আমার সমস্ত টার্গেট সিস্টেমগুলি আধুনিক ইন্টেল-ভিত্তিক তাই আসুন চূড়ান্তভাবে অনুকূল করা শুরু করুন !!!

সুতরাং আমি ম্যাট জে এর লুকিং কোডটি বেস হিসাবে ব্যবহার করেছি। যে সিস্টেমে আমি বেঞ্চমার্ক করছি সেগুলি হ'ল একটি আই 7 হ্যাভওল 4700eq।

ম্যাট জে এর 400,000 000 বাইট বিট ফ্লিপ করছে: প্রায় 0.272 সেকেন্ড।

আমি তখন এগিয়ে গিয়ে দেখার চেষ্টা করেছি যে ইন্টেলের আইএসপিসি সংকলকটি বিপরীতক্রমে গাণিতিকে ভেক্টরাইজ করতে পারে কিনা।

আমি এখানে আমার অনুসন্ধানের সাথে আপনাকে বিরক্ত করব না যেহেতু সংকলককে স্টাফ সন্ধান করতে আমি অনেক চেষ্টা করেছি, যাইহোক আমি প্রায় 0.15 সেকেন্ডের পারফরম্যান্স দিয়ে 400,000 000 বাইট বিটপ্লিপ করে শেষ করেছি। এটি একটি দুর্দান্ত হ্রাস কিন্তু আমার অ্যাপ্লিকেশনটির জন্য এখনও এটি খুব ধীরে ধীরে ..

সুতরাং লোকেরা আমাকে বিশ্বের দ্রুততম ইন্টেল ভিত্তিক বিটফ্লিপার উপস্থাপন করতে দেয়। এখানে আটকানো:

400000000 বাইট বিটফ্লিপ করার সময়: 0.050082 সেকেন্ড !!!!!

// Bitflip using AVX2 - The fastest Intel based bitflip in the world!!
// Made by Anders Cedronius 2014 (anders.cedronius (you know what) gmail.com)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

using namespace std;

#define DISPLAY_HEIGHT  4
#define DISPLAY_WIDTH   32
#define NUM_DATA_BYTES  400000000

// Constants (first we got the mask, then the high order nibble look up table and last we got the low order nibble lookup table)
__attribute__ ((aligned(32))) static unsigned char k1[32*3]={
        0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
        0x00,0x08,0x04,0x0c,0x02,0x0a,0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f,0x00,0x08,0x04,0x0c,0x02,0x0a,0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f,
        0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0
};

// The data to be bitflipped (+32 to avoid the quantization out of memory problem)
__attribute__ ((aligned(32))) static unsigned char data[NUM_DATA_BYTES+32]={};

extern "C" {
void bitflipbyte(unsigned char[],unsigned int,unsigned char[]);
}

int main()
{

    for(unsigned int i = 0; i < NUM_DATA_BYTES; i++)
    {
        data[i] = rand();
    }

    printf ("\r\nData in(start):\r\n");
    for (unsigned int j = 0; j < 4; j++)
    {
        for (unsigned int i = 0; i < DISPLAY_WIDTH; i++)
        {
            printf ("0x%02x,",data[i+(j*DISPLAY_WIDTH)]);
        }
        printf ("\r\n");
    }

    printf ("\r\nNumber of 32-byte chunks to convert: %d\r\n",(unsigned int)ceil(NUM_DATA_BYTES/32.0));

    double start_time = omp_get_wtime();
    bitflipbyte(data,(unsigned int)ceil(NUM_DATA_BYTES/32.0),k1);
    double end_time = omp_get_wtime();

    printf ("\r\nData out:\r\n");
    for (unsigned int j = 0; j < 4; j++)
    {
        for (unsigned int i = 0; i < DISPLAY_WIDTH; i++)
        {
            printf ("0x%02x,",data[i+(j*DISPLAY_WIDTH)]);
        }
        printf ("\r\n");
    }
    printf("\r\n\r\nTime to bitflip %d bytes: %f seconds\r\n\r\n",NUM_DATA_BYTES, end_time-start_time);

    // return with no errors
    return 0;
}

প্রিন্টফগুলি ডিবাগিংয়ের জন্য ..

ওয়ার্কহর্স এখানে:

bits 64
global bitflipbyte

bitflipbyte:    
        vmovdqa     ymm2, [rdx]
        add         rdx, 20h
        vmovdqa     ymm3, [rdx]
        add         rdx, 20h
        vmovdqa     ymm4, [rdx]
bitflipp_loop:
        vmovdqa     ymm0, [rdi] 
        vpand       ymm1, ymm2, ymm0 
        vpandn      ymm0, ymm2, ymm0 
        vpsrld      ymm0, ymm0, 4h 
        vpshufb     ymm1, ymm4, ymm1 
        vpshufb     ymm0, ymm3, ymm0         
        vpor        ymm0, ymm0, ymm1
        vmovdqa     [rdi], ymm0
        add     rdi, 20h
        dec     rsi
        jnz     bitflipp_loop
        ret

কোডটি 32 বাইট নেয় তারপর নিবলগুলি আটকান। উচ্চ স্তনবৃন্তটি সরাসরি ৪ এর মধ্যে স্থানান্তরিত হবে Then তারপরে আমি ভিপিশুফবি এবং ymm4 / ymm3 কে সারণী হিসাবে সন্ধান করব। আমি একটি একক দেখার টেবিল ব্যবহার করতে পারতাম তবে তারপরে আমাকে আবার একসাথে নিবারগুলি ওরিংয়ের আগে বামে স্থানান্তরিত করতে হবে।

বিটগুলি উল্টানোর আরও দ্রুত উপায় রয়েছে। তবে আমি একক থ্রেড এবং সিপিইউতে আবদ্ধ তাই এটি সবচেয়ে দ্রুত অর্জন করতে পেরেছিলাম। আপনি একটি দ্রুত সংস্করণ করতে পারেন?

দয়া করে ইনটেল সি / সি ++ কম্পাইলার অন্তর্নিহিত সমতুল্য আদেশগুলি ব্যবহার সম্পর্কে কোনও মন্তব্য করবেন না ...


2
আপনি এই তুলনায় আরও বেশি upvotes প্রাপ্য। আমি জানতাম যে এটি করা উচিত pshub, কারণ সর্বোপরি সেরা পপকাউন্ট এটির সাথেও করা হয়ে যায়! আপনার জন্য না থাকলে আমি এখানে এটি লিখতাম। যশ।
আইভিলনোটেক্সিস্ট আইডোনোটেক্সিস্ট 21

3
ধন্যবাদ! 'পপসেন্ট' আমার আরেকটি প্রিয় বিষয়;) আমার বিএমআই 2 সংস্করণটি দেখুন: ফলাফল = __ tzcnt_u64 (pe _pext_u64 (ডেটা [i], ডেটা [i]));
অ্যান্ডারস সিড্রোনিয়াস

3
Asm ফাইলটির নাম দিন: bitflip_asm.s তারপরে: yasm -f elf64 bitflip_asm.s সি ফাইলটির নাম দিন: bitflip.c তারপরে: g ++ -fopenmp bitflip.c bitflip_asm.o -o bitflip এটি চালিয়ে যায়।
অ্যান্ডারস সিড্রোনিয়াস

4
ইন্টেল CPU- র জন্য মৃত্যুদন্ড ইউনিট আছে popcnt, tzcntএবং pextযে তাই বন্দর 1. উপর pextবা tzcntআপনাকে খরচ একটি popcntথ্রুপুট করুন। যদি আপনার ডেটা এল 1 ডি ক্যাশে গরম থাকে তবে ইন্টেল সিপিইউতে একটি অ্যারের পপকাউন্ট করার দ্রুততম উপায় হল অ্যাভিএক্স 2 pshufb। (রিজেনের প্রতি ক্লক popcntথ্রুপুট 4 রয়েছে তাই সম্ভবত এটি সর্বোত্তম) তবে বুলডোজার-পরিবারে প্রতি 4 টি ক্লকpopcnt r64,r64 থ্রুপুট রয়েছে ... Agner.org/optimize )।
পিটার কর্ডস

4
আমি নিজেই একটি আন্তঃব্যক্তি সংস্করণ ব্যবহার করছি। তবে আমি যখন উত্তর দিয়েছিলাম তখন আমার কাছে যা ছিল তা আমি পোস্ট করেছি এবং আমি পূর্ববর্তী পোস্টগুলি থেকে জানি যে যত তাড়াতাড়ি আমি এসেম্বলারকে লিখি একটি স্মার্ট আলেক সর্বদা নির্দেশ করে যে আমার এটি অন্তর্নিহিতগুলিতে করা উচিত ছিল। আমি যখন বিকাশ করি তখন আমি প্রথমে এসেম্বলার লিখি, যখন আমি ফলাফলটি পছন্দ করি তখন আমি অন্তর্নিহিতগুলিতে চলে যাই .. এটাই আমি .. আমার উত্তরটি পোস্ট করার সাথে সাথেই ঘটেছিল যখন আমার কেবল আমার 'পরীক্ষা' এসেম্বলার সংস্করণ ছিল।
অ্যান্ডারস সিড্রোনিয়াস

16

এটি পুনরাবৃত্তি পছন্দ যারা ভাবেন জন্য অন্য সমাধান।

ধারণাটি সহজ। অর্ধেক দ্বারা ইনপুট বিভক্ত করুন এবং দুটি অংশটি অদলবদল করুন, এটি একক বিট না পৌঁছা পর্যন্ত চালিয়ে যান।

Illustrated in the example below.

Ex : If Input is 00101010   ==> Expected output is 01010100

1. Divide the input into 2 halves 
    0010 --- 1010

2. Swap the 2 Halves
    1010     0010

3. Repeat the same for each half.
    10 -- 10 ---  00 -- 10
    10    10      10    00

    1-0 -- 1-0 --- 1-0 -- 0-0
    0 1    0 1     0 1    0 0

Done! Output is 01010100

এটি সমাধানের জন্য এখানে একটি পুনরাবৃত্ত ফাংশন। (দ্রষ্টব্য আমি স্বাক্ষরবিহীন ইনট ব্যবহার করেছি, সুতরাং এটি আকারের (স্বাক্ষরবিহীন) * 8 বিট পর্যন্ত ইনপুটগুলির জন্য কাজ করতে পারে।

রিকার্সিভ ফাংশনটিতে 2 টি প্যারামিটার লাগে - যার বিটগুলি বিপরীত করা দরকার এবং মানটিতে বিটের সংখ্যা।

int reverse_bits_recursive(unsigned int num, unsigned int numBits)
{
    unsigned int reversedNum;;
    unsigned int mask = 0;

    mask = (0x1 << (numBits/2)) - 1;

    if (numBits == 1) return num;
    reversedNum = reverse_bits_recursive(num >> numBits/2, numBits/2) |
                   reverse_bits_recursive((num & mask), numBits/2) << numBits/2;
    return reversedNum;
}

int main()
{
    unsigned int reversedNum;
    unsigned int num;

    num = 0x55;
    reversedNum = reverse_bits_recursive(num, 8);
    printf ("Bit Reversal Input = 0x%x Output = 0x%x\n", num, reversedNum);

    num = 0xabcd;
    reversedNum = reverse_bits_recursive(num, 16);
    printf ("Bit Reversal Input = 0x%x Output = 0x%x\n", num, reversedNum);

    num = 0x123456;
    reversedNum = reverse_bits_recursive(num, 24);
    printf ("Bit Reversal Input = 0x%x Output = 0x%x\n", num, reversedNum);

    num = 0x11223344;
    reversedNum = reverse_bits_recursive(num,32);
    printf ("Bit Reversal Input = 0x%x Output = 0x%x\n", num, reversedNum);
}

এটি আউটপুট:

Bit Reversal Input = 0x55 Output = 0xaa
Bit Reversal Input = 0xabcd Output = 0xb3d5
Bit Reversal Input = 0x123456 Output = 0x651690
Bit Reversal Input = 0x11223344 Output = 0x22cc4488

এই পদ্ধতির 24-বিট উদাহরণ (3 য়) উপর কাজ করতে ব্যর্থ হয়? আমি সি এবং বিটওয়াইজ অপারেটরগুলির সাথে বেশ পরিচিত নই তবে আপনার পদ্ধতির ব্যাখ্যা থেকে আমি অনুমান করছি 24-> 12-> 6-> 3 (3 বিট বিভক্ত হয়ে অসম্পূর্ণ 3)। যেমনটি numBitsঅন্তর্নিহিত, আপনি যখন ফাংশন পরমের জন্য 3 দ্বারা 2 বিভক্ত করবেন তখন এটি গোল করে 1 হবে?
ব্রেনান

13

ভাল এটি ম্যাট জে এর মতো উত্তর অবশ্যই হবে না তবে আশা করি এটি এখনও কার্যকর হবে।

size_t reverse(size_t n, unsigned int bytes)
{
    __asm__("BSWAP %0" : "=r"(n) : "0"(n));
    n >>= ((sizeof(size_t) - bytes) * 8);
    n = ((n & 0xaaaaaaaaaaaaaaaa) >> 1) | ((n & 0x5555555555555555) << 1);
    n = ((n & 0xcccccccccccccccc) >> 2) | ((n & 0x3333333333333333) << 2);
    n = ((n & 0xf0f0f0f0f0f0f0f0) >> 4) | ((n & 0x0f0f0f0f0f0f0f0f) << 4);
    return n;
}

এটি হ'ল ম্যাট-এর সেরা অ্যালগরিদম হিসাবে একই ধারণা ব্যতীত বিএসডাব্লুএপি নামক এই ছোট্ট নির্দেশ যা একটি 64৪-বিটের সংখ্যার বাইটগুলি (বিট নয়) অদলবদল করে। সুতরাং বি 7, বি 6, বি 5, বি 4, বি 3, বি 2, বি 1, বি 0 বি 0, বি 1, বি 2, বি 3, বি 4, বি 5, বি 6, বি 7 হয়ে যায়। যেহেতু আমরা একটি 32-বিট নম্বর নিয়ে কাজ করছি আমাদের 32-বিট নীচে আমাদের বাইট-অদলবদল নম্বরটি স্থানান্তর করতে হবে। এটি কেবল আমাদের তৈরি প্রতিটি বাইটের 8 টি বিট অদলবদলের কাজটি ছেড়ে দেয় এবং ভয়েলা! সম্পন্ন করা হয়েছে.

সময়: আমার মেশিনে, ম্যাট-এর অ্যালগরিদম পরীক্ষার জন্য ~ 0.52 সেকেন্ডে ছুটেছিল। আমার পরীক্ষায় প্রায় 0.42 সেকেন্ডের মধ্যে দৌড়েছিল। 20% দ্রুত খারাপ বলে আমি মনে করি না।

আপনি যদি বিএসডব্লিউপি উইকিপিডিয়ায় বিএসডাব্লুএপি- র নির্দেশকে বিএসডাব্লুএপি-তে যোগ করেছিলেন বলে নির্দেশনাটি ১৯৮৯ সালে প্রকাশিত ৮০৮66-এর সাথে তালিকাভুক্ত করে থাকেন, তবে এটিও লক্ষ করা উচিত যে উইকিপিডিয়া আরও জানিয়েছে যে এই নির্দেশিকাটি কেবলমাত্র 32 বিট রেজিস্টারে কাজ করে যা পরিষ্কারভাবে নয় আমার মেশিনের ক্ষেত্রে, এটি কেবলমাত্র 64৪-বিট রেজিস্টারে কাজ করে।

এই পদ্ধতিটি যে কোনও ইন্টিগ্রাল ডেটাটাইপের জন্য সমানভাবে কাজ করবে যাতে পছন্দসই বাইটের সংখ্যাটি পাস করে পদ্ধতিটি তুচ্ছভাবে সাধারণ করা যায়:

    size_t reverse(size_t n, unsigned int bytes)
    {
        __asm__("BSWAP %0" : "=r"(n) : "0"(n));
        n >>= ((sizeof(size_t) - bytes) * 8);
        n = ((n & 0xaaaaaaaaaaaaaaaa) >> 1) | ((n & 0x5555555555555555) << 1);
        n = ((n & 0xcccccccccccccccc) >> 2) | ((n & 0x3333333333333333) << 2);
        n = ((n & 0xf0f0f0f0f0f0f0f0) >> 4) | ((n & 0x0f0f0f0f0f0f0f0f) << 4);
        return n;
    }

যার পরে এটি বলা যেতে পারে:

    n = reverse(n, sizeof(char));//only reverse 8 bits
    n = reverse(n, sizeof(short));//reverse 16 bits
    n = reverse(n, sizeof(int));//reverse 32 bits
    n = reverse(n, sizeof(size_t));//reverse 64 bits

সংকলক অতিরিক্ত প্যারামিটার দূরে অপ্টিমাইজ করতে সক্ষম হওয়া উচিত (কম্পাইলারটি ফাংশনটি ইনলাইন করে ধরে নিচ্ছে) এবং কেসটির জন্য sizeof(size_t)ডান-শিফট পুরোপুরি মুছে ফেলা হবে। নোট করুন যে জিসিসি কমপক্ষে বিএসডাব্লুএপি এবং পাস হলে ডান-শিফট সরাতে সক্ষম নয় sizeof(char)


2
ইন্টেল ইন্সট্রাকশন সেট রেফারেন্স ভলিউম 2 এ অনুসারে ( বিসিএল / কনটেন্ট /www/us/en/processors/…) দুটি বিএসডাব্লুএইপ নির্দেশনা রয়েছে: বিএসডাব্লুএপ আর 32 (32 বিট রেজিস্টারে কাজ করছে), যা 0 এফ সি 8 + আরডি হিসাবে এনকোড করা আছে এবং বিএসডাব্লুপি আর (৪ (bit৪ বিট রেজিস্টারে কাজ করছে), যা REX.W + 0F C8 + rd হিসাবে এনকোড রয়েছে।
নুবোক

আপনি বলছেন এটি এর মতো ব্যবহার করা যেতে পারে: "এন = বিপরীত (এন, সাইজফ (সাইজ_টি)); // বিপরীত 64৪ বিট" তবে সমস্ত ধ্রুবককে bit৪ বিট পর্যন্ত বাড়ানো না হলে এটি কেবল ফলাফলের 32 বিট দেয় তবে এটি কাজ করে।
রাজকোস্টো

সিরাজী কোস্টো সি ++ ১১ এর মতো অনুমোদিত ধরণের unsigned long long int
সংখ্যার সাথে

ঠিক আছে? আমি কেবল বলছি যে যদি আপনি এটি 64 বিট মানগুলিতে কাজ করতে চান তবে আপনাকে আপনার আক্ষরিক প্রসারকে বাড়াতে হবে (উদাহরণস্বরূপ তারা 0xf0f0f0f0f0f0f0f0f0ull, উদাহরণস্বরূপ), অন্যথায় ফলাফলের উচ্চ 32 বিটগুলি সমস্ত 0s হবে।
রাজকোস্টো

@ রাজকোস্টো আহ, আমি আপনার প্রথম মন্তব্যটি ভুল বুঝেছিলাম, আমি এখনই তা স্থির করে
রেখেছি

13

অ্যান্ডারস সিড্রোনিয়াসের উত্তর এমন লোকদের জন্য দুর্দান্ত সমাধান সরবরাহ করে যাদের AVX2 সমর্থন সহ একটি x86 সিপিইউ রয়েছে। অ্যাভিএক্স সমর্থন ছাড়াই বা x-x86 প্ল্যাটফর্ম ছাড়া x86 প্ল্যাটফর্মের জন্য, নিম্নলিখিত বাস্তবায়নগুলি কার্যকরভাবে কাজ করা উচিত।

প্রথম কোডটি ক্লাসিক বাইনারি পার্টিশন পদ্ধতির একটি বৈকল্পিক যা বিভিন্ন এআরএম প্রসেসরের জন্য দরকারী শিফট-প্লাস-লজিক আইডিয়ামটি সর্বাধিকতর করতে কোড করে। এছাড়াও, এটি অন-ফ্লাই মাস্ক জেনারেশন ব্যবহার করে যা আরআইএসসি প্রসেসরের পক্ষে উপকারী হতে পারে যা অন্যথায় প্রতিটি 32-বিট মাস্ক মান লোড করার জন্য একাধিক নির্দেশনার প্রয়োজন। X86 প্ল্যাটফর্মগুলির জন্য সংকলকগুলি রান মাসের চেয়ে কমপাইল সময়ে সমস্ত মাস্কগুলি গণনা করার জন্য ধ্রুবক প্রচার ব্যবহার করা উচিত।

/* Classic binary partitioning algorithm */
inline uint32_t brev_classic (uint32_t a)
{
    uint32_t m;
    a = (a >> 16) | (a << 16);                            // swap halfwords
    m = 0x00ff00ff; a = ((a >> 8) & m) | ((a << 8) & ~m); // swap bytes
    m = m^(m << 4); a = ((a >> 4) & m) | ((a << 4) & ~m); // swap nibbles
    m = m^(m << 2); a = ((a >> 2) & m) | ((a << 2) & ~m);
    m = m^(m << 1); a = ((a >> 1) & m) | ((a << 1) & ~m);
    return a;
}

"আর্ট অফ কম্পিউটার প্রোগ্রামিং" এর ভলিউম 4 এ-তে, ডি নুথ বিটগুলি বিপরীত করার চতুর উপায়গুলি দেখায় যা কিছুটা আশ্চর্যজনকভাবে ক্লাসিকাল বাইনারি বিভাজন অ্যালগরিদমের চেয়ে কম অপারেশন প্রয়োজন। 32-বিট অপারেটরগুলির জন্য এই জাতীয় একটি অ্যালগরিদম, যা আমি টিএওসিপিতে পাই না, হ্যাকার ডিলাইট ওয়েবসাইটে এই নথিতে দেখানো হয়েছে ।

/* Knuth's algorithm from http://www.hackersdelight.org/revisions.pdf. Retrieved 8/19/2015 */
inline uint32_t brev_knuth (uint32_t a)
{
    uint32_t t;
    a = (a << 15) | (a >> 17);
    t = (a ^ (a >> 10)) & 0x003f801f; 
    a = (t + (t << 10)) ^ a;
    t = (a ^ (a >>  4)) & 0x0e038421; 
    a = (t + (t <<  4)) ^ a;
    t = (a ^ (a >>  2)) & 0x22488842; 
    a = (t + (t <<  2)) ^ a;
    return a;
}

ইন্টেল সংকলক সি / সি ++ সংকলক 13.1.3.198 ব্যবহার করে উপরের দুটি ফাংশন নিখরচায়ভাবে নিবন্ধকরণকারী নিবন্ধগুলিকে স্ব-ভেক্টরাইজ করে XMM। তারা অনেক চেষ্টা ছাড়াই ম্যানুয়ালি ভেক্টরাইজড হতে পারে।

আমার আইভিব্রিজে জিওন ই 3 1270v2 এ, অটো-ভেক্টরাইজড কোড ব্যবহার করে, 100 মিলিয়ন uint32_tশব্দ ব্যবহার করে 0.070 সেকেন্ডে brev_classic()এবং 0.068 সেকেন্ড ব্যবহার করে বিট-বিপরীত হয়েছিল brev_knuth()। আমার মাপকাঠিটি সিস্টেম মেমরির ব্যান্ডউইথ দ্বারা সীমাবদ্ধ না ছিল তা নিশ্চিত করার জন্য আমি যত্ন নিয়েছিলাম।


2
@ জোয়েল স্নাইডার আমি ধরে নিই যে আপনি "প্রচুর যাদু সংখ্যা" দ্বারা প্রাথমিকভাবে উল্লেখ করছেন brev_knuth()? হ্যাকার্স ডিলাইট থেকে পিডিএফের গুণাবলী থেকে মনে হয় যে এই সংখ্যাগুলি সরাসরি নূথের। ধ্রুবকগুলি কীভাবে উদ্ভূত হয়েছিল, বা কীভাবে সারণী শব্দগুলির আকারের জন্য ডাইভারিং ধ্রুবকগুলি এবং শিফ্ট ফ্যাক্টরগুলি সম্পর্কে যেতে হবে তা ব্যাখ্যা করার জন্য আমি টিএওসিপিতে অন্তর্নিহিত নকশার নীতিগুলির নুথের বর্ণনাকে বুঝতে পেরেছি বলে দাবি করতে পারি না।
njuffa

8

অনুমান করা হচ্ছে যে আপনার কাছে বিটগুলির একটি অ্যারে রয়েছে, এটি সম্পর্কে: 1. এমএসবি থেকে শুরু করে, বিটগুলি একে একে একটি স্ট্যাকের মধ্যে ধাক্কা। ২. এই স্ট্যাক থেকে অন্য অ্যারেতে পপ বিট (বা একই অ্যারে আপনি যদি স্থান বাঁচাতে চান তবে) এমএসবিতে প্রথম পপড বিট স্থাপন করে এবং সেখান থেকে কম গুরুত্বপূর্ণ বিটগুলিতে চলে যান।

Stack stack = new Stack();
Bit[] bits = new Bit[] { 0, 0, 1, 0, 0, 0, 0, 0 };

for (int i = 0; i < bits.Length; i++) 
{
    stack.push(bits[i]);
}

for (int i = 0; i < bits.Length; i++)
{
    bits[i] = stack.pop();
}

3
এটি আমাকে হাসিয়ে দিয়েছে :) আমি অনুকূলিত সিতে উপরে উল্লিখিত একটির বিরুদ্ধে এই সি # সমাধানের একটি বেঞ্চমার্ক দেখতে পছন্দ করব
ম্যাট জে

LOL ... তবে আরে! 'সেরা অ্যালগরিদমের' বিশেষ্যটি একটি দুর্দান্ত বিষয়গত জিনিস: ডি
ফ্রেডেরিক দ্য ফুল

7

নেটিভ এআরএম নির্দেশনা "rbit" এটি 1 সিপিইউ চক্র এবং 1 টি অতিরিক্ত সিপিইউ রেজিস্ট্রার দিয়ে করতে পারে, বীট করা অসম্ভব।


6

এটি কোনও মানুষের পক্ষে কাজ নয়! ... তবে একটি মেশিনের জন্য উপযুক্ত

এই প্রশ্নটি প্রথম জিজ্ঞাসা করা হয়েছিল তার 6 বছর পরে এটি 2015 is সংকলকগণ তখন থেকে আমাদের মাস্টার হয়ে গেছে এবং মানুষ হিসাবে আমাদের কাজ কেবল তাদের সহায়তা করা। সুতরাং মেশিনে আমাদের উদ্দেশ্যগুলি দেওয়ার সর্বোত্তম উপায় কী?

বিট-রিভার্সাল এতটাই সাধারণ যে আপনাকে ভাবতে হবে যে x86 এর বর্ধমান আইএসএ কেন এটি করার কোনও নির্দেশ অন্তর্ভুক্ত করে না।

কারণ: আপনি যদি সংকলককে আপনার সত্যিকারের সংক্ষিপ্ত অভিপ্রায় দেন তবে বিট বিপরীতে কেবলমাত্র ~ 20 সিপিইউ চক্র নেওয়া উচিত । কীভাবে বিপরীতমুখী () তৈরি করতে এবং এটি ব্যবহার করতে হয় তা আমি আপনাকে দেখাতে পারি:

#include <inttypes.h>
#include <stdio.h>

uint64_t reverse(const uint64_t n,
                 const uint64_t k)
{
        uint64_t r, i;
        for (r = 0, i = 0; i < k; ++i)
                r |= ((n >> i) & 1) << (k - i - 1);
        return r;
}

int main()
{
        const uint64_t size = 64;
        uint64_t sum = 0;
        uint64_t a;
        for (a = 0; a < (uint64_t)1 << 30; ++a)
                sum += reverse(a, size);
        printf("%" PRIu64 "\n", sum);
        return 0;
}

এই নমুনা প্রোগ্রামটি ক্ল্যাং সংস্করণ> = 3.6, -O3, -মার্চ = নেটিভ (হ্যাসওয়েলের সাথে পরীক্ষিত) দিয়ে সংকলন করা, 11 সেকেন্ডের প্রক্রিয়াকরণের time 1 বিলিয়ন বিপরীত () এর রানটাইম সহ নতুন এভিএক্স 2 নির্দেশাবলী ব্যবহার করে শিল্পকর্ম-মানের কোড দেয় । বিপরীতে () প্রতি 10 ডলার হয়,

  • একক বড় বড় অ্যারের জন্য একবার র‍্যাম অ্যাক্সেস করতে সময় লাগে আপনি 10 বিপরীত () গুলি ফিট করতে পারেন!
  • L2 ক্যাশে LUT দুবার অ্যাক্সেস করতে যে সময় লাগে আপনি তার মধ্যে 1 বিপরীত () ফিট করতে পারেন।

ক্যাভ্যাট: এই নমুনা কোডটি কয়েক বছরের জন্য একটি শালীন মানদণ্ড হিসাবে রাখা উচিত, তবে শেষ পর্যন্ত এটির বয়স দেখাতে শুরু করবে একবার সংকলকরা সত্যিকারের কোনও কিছুর পরিবর্তে চূড়ান্ত ফলাফলটি প্রিন্ট করার জন্য মেইন () কে উপযুক্ত করতে যথেষ্ট স্মার্ট হয়। তবে আপাতত এটি বিপরীত () প্রদর্শন করাতে কাজ করে।


Bit-reversal is so common...আমি যে বিষয়ে জানি না. আমি এমন কোডের সাথে কাজ করি যা প্রতিদিন বিট লেভেলে ডেটা নিয়ে কার্যত ডিল করে এবং এই নির্দিষ্ট প্রয়োজনটি আমি কখনও মনে করতে পারি না। কোন পরিস্থিতিতে আপনার এটির প্রয়োজন? - এটি নয় যে এটি নিজের মতো করে সমাধান করা কোনও আকর্ষণীয় সমস্যা নয়।
500 - অভ্যন্তরীণ সার্ভার ত্রুটি

@ 500-অভ্যন্তরীণ সার্ভারএরআরআর আমি দ্রুত, সাসিনেক্ট ডেটা স্ট্রাকচারের সাথে ব্যাকরণ সহকারে অনেক বার এই ফাংশনটির প্রয়োজন শেষ করি। বিটারে হিসাবে এনকোড করা একটি সাধারণ বাইনারি গাছটি "বড় এন্ডিয়ান" ক্রমে ব্যাকরণের অনুমান করে। তবে উন্নত সাধারণীকরণের জন্য যদি আপনি বিট-রিভার্সাল ক্রমুটিশন দ্বারা নোডগুলি দিয়ে অদলবদল করে একটি বিট (বিটারে) তৈরি করেন তবে শিখেছি ব্যাকরণের স্ট্রিংগুলি "লিটল এন্ডিয়ান" তে রয়েছে। এই স্যুইচিং আপনাকে স্থির পূর্ণসংখ্যার আকারের পরিবর্তে পরিবর্তনশীল দৈর্ঘ্যের স্ট্রিংগুলি নির্ধারণ করতে দেয়। এই পরিস্থিতি পাশাপাশি দক্ষ FFT অনেক পপ আপ: দেখুন en.wikipedia.org/wiki/Bit-reversal_permutation

1
ধন্যবাদ, আমি কোনওভাবেই অনুধাবন করতে পেরেছি যে এফএফটি আপনার উত্তরের সাথে জড়িত থাকতে পারে :)
500 - অভ্যন্তরীণ সার্ভার ত্রুটি

কেন শুধু 20 চক্র? কোন আর্কিটেকচার? মানবজাতি এবং আমাদের উত্সাহ অবসান না হওয়া অবধি কি ভবিষ্যতের সমস্ত অতি প্রশস্ত ভিআইএলডাব্লু আর্কিটেকচারের জন্য এটি সত্য? কেবল প্রশ্ন, কোনও উত্তর নেই ... আবার জাহান্নামে যান
Quonux


5

আমি জানি এটি সি নয় তবে এএসএম:

var1 dw 0f0f0
clc
     push ax
     push cx
     mov cx 16
loop1:
     shl var1
     shr ax
loop loop1
     pop ax
     pop cx

এটি ক্যারি বিটের সাথে কাজ করে, তাই আপনি পতাকাগুলিও সংরক্ষণ করতে পারেন


1
আমার ধারণা আপনি এসএম কীওয়ার্ডটি ব্যবহার করতে পারেন যা বেশ দ্রুত হবে।
টম

এটি এমনকি কাজ করে না। আমি মনে করি আপনি rclসিএফ স্থানান্তর করতে চান var1, কেবল পরিবর্তে shlযা পতাকাগুলি পড়ে না। (বা adc dx,dx) এমনকি এটি ঠিক সঙ্গে, এই হাস্যকর ধীর হয়, ধীর ব্যবহার loopনির্দেশ এবং পালন var1মেমরি! আসলে আমি মনে করি এটি এক্স এর আউটপুট উত্পাদন করবে বলে মনে করা হচ্ছে, তবে এটি ফলাফলের উপরে এক্স এর পুরানো মানটিকে সংরক্ষণ / পুনরুদ্ধার করে।
পিটার কর্ডেস

4

স্বল্প স্মৃতি এবং দ্রুততম সহ বাস্তবায়ন।

private Byte  BitReverse(Byte bData)
    {
        Byte[] lookup = { 0, 8,  4, 12, 
                          2, 10, 6, 14 , 
                          1, 9,  5, 13,
                          3, 11, 7, 15 };
        Byte ret_val = (Byte)(((lookup[(bData & 0x0F)]) << 4) + lookup[((bData & 0xF0) >> 4)]);
        return ret_val;
    }

4

ঠিক আছে, এটি মূলত প্রথম "বিপরীত ()" এর মতো তবে এটি 64৪ বিট এবং নির্দেশের প্রবাহ থেকে লোড করার জন্য কেবল একটি তাত্ক্ষণিক মুখোশ প্রয়োজন। জিসিসি জাম্প ছাড়াই কোড তৈরি করে, তাই এটি বেশ দ্রুত হওয়া উচিত।

#include <stdio.h>

static unsigned long long swap64(unsigned long long val)
{
#define ZZZZ(x,s,m) (((x) >>(s)) & (m)) | (((x) & (m))<<(s));
/* val = (((val) >>16) & 0xFFFF0000FFFF) | (((val) & 0xFFFF0000FFFF)<<16); */

val = ZZZZ(val,32,  0x00000000FFFFFFFFull );
val = ZZZZ(val,16,  0x0000FFFF0000FFFFull );
val = ZZZZ(val,8,   0x00FF00FF00FF00FFull );
val = ZZZZ(val,4,   0x0F0F0F0F0F0F0F0Full );
val = ZZZZ(val,2,   0x3333333333333333ull );
val = ZZZZ(val,1,   0x5555555555555555ull );

return val;
#undef ZZZZ
}

int main(void)
{
unsigned long long val, aaaa[16] =
 { 0xfedcba9876543210,0xedcba9876543210f,0xdcba9876543210fe,0xcba9876543210fed
 , 0xba9876543210fedc,0xa9876543210fedcb,0x9876543210fedcba,0x876543210fedcba9
 , 0x76543210fedcba98,0x6543210fedcba987,0x543210fedcba9876,0x43210fedcba98765
 , 0x3210fedcba987654,0x210fedcba9876543,0x10fedcba98765432,0x0fedcba987654321
 };
unsigned iii;

for (iii=0; iii < 16; iii++) {
    val = swap64 (aaaa[iii]);
    printf("A[]=%016llX Sw=%016llx\n", aaaa[iii], val);
    }
return 0;
}

4

আমি কৌতূহলী ছিলাম কত দ্রুত স্পষ্ট কাঁচা ঘূর্ণন হবে। আমার মেশিনে (i7 @ 2600), গড় 1,500,150,000 পুনরাবৃত্তির জন্য ছিল27.28 ns (131,071 64৪-বিট পূর্ণসংখ্যার এ এলোমেলো সেট)।

সুবিধা: প্রয়োজনীয় মেমরির পরিমাণ কম এবং কোডটি সহজ। আমি বলব এটিও এত বড় নয়। প্রয়োজনীয় সময়টি কোনও ইনপুট (128 পাটিগণিত শিফট অপারেশন + 64 লজিকাল এবং ক্রিয়াকলাপগুলি + 64 লজিকাল ও অপারেশন) এর জন্য অনুমানযোগ্য এবং ধ্রুবক।

আমি @ ম্যাট জে দ্বারা প্রাপ্ত সেরা সময়ের সাথে তুলনা করেছি - যার কাছে স্বীকৃত উত্তর রয়েছে। যদি আমি তার উত্তরটি সঠিকভাবে পড়ি, তবে তার সেরাটি হ'ল পুনরাবৃত্তির 0.631739জন্য কয়েক সেকেন্ড 1,000,000, যা 631 nsপ্রতি ঘূর্ণনের গড়ের দিকে নিয়ে যায় ।

আমি যে কোড স্নিপেট ব্যবহার করেছি তা নীচে এটি:

unsigned long long reverse_long(unsigned long long x)
{
    return (((x >> 0) & 1) << 63) |
           (((x >> 1) & 1) << 62) |
           (((x >> 2) & 1) << 61) |
           (((x >> 3) & 1) << 60) |
           (((x >> 4) & 1) << 59) |
           (((x >> 5) & 1) << 58) |
           (((x >> 6) & 1) << 57) |
           (((x >> 7) & 1) << 56) |
           (((x >> 8) & 1) << 55) |
           (((x >> 9) & 1) << 54) |
           (((x >> 10) & 1) << 53) |
           (((x >> 11) & 1) << 52) |
           (((x >> 12) & 1) << 51) |
           (((x >> 13) & 1) << 50) |
           (((x >> 14) & 1) << 49) |
           (((x >> 15) & 1) << 48) |
           (((x >> 16) & 1) << 47) |
           (((x >> 17) & 1) << 46) |
           (((x >> 18) & 1) << 45) |
           (((x >> 19) & 1) << 44) |
           (((x >> 20) & 1) << 43) |
           (((x >> 21) & 1) << 42) |
           (((x >> 22) & 1) << 41) |
           (((x >> 23) & 1) << 40) |
           (((x >> 24) & 1) << 39) |
           (((x >> 25) & 1) << 38) |
           (((x >> 26) & 1) << 37) |
           (((x >> 27) & 1) << 36) |
           (((x >> 28) & 1) << 35) |
           (((x >> 29) & 1) << 34) |
           (((x >> 30) & 1) << 33) |
           (((x >> 31) & 1) << 32) |
           (((x >> 32) & 1) << 31) |
           (((x >> 33) & 1) << 30) |
           (((x >> 34) & 1) << 29) |
           (((x >> 35) & 1) << 28) |
           (((x >> 36) & 1) << 27) |
           (((x >> 37) & 1) << 26) |
           (((x >> 38) & 1) << 25) |
           (((x >> 39) & 1) << 24) |
           (((x >> 40) & 1) << 23) |
           (((x >> 41) & 1) << 22) |
           (((x >> 42) & 1) << 21) |
           (((x >> 43) & 1) << 20) |
           (((x >> 44) & 1) << 19) |
           (((x >> 45) & 1) << 18) |
           (((x >> 46) & 1) << 17) |
           (((x >> 47) & 1) << 16) |
           (((x >> 48) & 1) << 15) |
           (((x >> 49) & 1) << 14) |
           (((x >> 50) & 1) << 13) |
           (((x >> 51) & 1) << 12) |
           (((x >> 52) & 1) << 11) |
           (((x >> 53) & 1) << 10) |
           (((x >> 54) & 1) << 9) |
           (((x >> 55) & 1) << 8) |
           (((x >> 56) & 1) << 7) |
           (((x >> 57) & 1) << 6) |
           (((x >> 58) & 1) << 5) |
           (((x >> 59) & 1) << 4) |
           (((x >> 60) & 1) << 3) |
           (((x >> 61) & 1) << 2) |
           (((x >> 62) & 1) << 1) |
           (((x >> 63) & 1) << 0);
}

@ গ্রেইবার্ড আমি নিশ্চিত না যে আমি আপনার প্রশ্নটি বুঝতে পেরেছি।
মেরিয়ান আদম

বাগটি লক্ষ্য করার জন্য ধন্যবাদ, আমি প্রদত্ত কোড নমুনাটি ঠিক করেছি।
মেরিয়ান অ্যাডাম

3

আপনি স্ট্যান্ডার্ড টেম্পলেট লাইব্রেরিটি ব্যবহার করতে চাইতে পারেন। এটি উপরে বর্ণিত কোডের চেয়ে ধীর হতে পারে। যাইহোক, এটি আমার কাছে আরও স্পষ্ট এবং বুঝতে সহজ বলে মনে হচ্ছে।

 #include<bitset>
 #include<iostream>


 template<size_t N>
 const std::bitset<N> reverse(const std::bitset<N>& ordered)
 {
      std::bitset<N> reversed;
      for(size_t i = 0, j = N - 1; i < N; ++i, --j)
           reversed[j] = ordered[i];
      return reversed;
 };


 // test the function
 int main()
 {
      unsigned long num; 
      const size_t N = sizeof(num)*8;

      std::cin >> num;
      std::cout << std::showbase << std::hex;
      std::cout << "ordered  = " << num << std::endl;
      std::cout << "reversed = " << reverse<N>(num).to_ulong()  << std::endl;
      std::cout << "double_reversed = " << reverse<N>(reverse<N>(num)).to_ulong() << std::endl;  
 }

2

জাতিবাচক

সি কোড। উদাহরণ হিসাবে 1 বাইট ইনপুট ডেটা নম্বর ব্যবহার করে।

    unsigned char num = 0xaa;   // 1010 1010 (aa) -> 0101 0101 (55)
    int s = sizeof(num) * 8;    // get number of bits
    int i, x, y, p;
    int var = 0;                // make var data type to be equal or larger than num

    for (i = 0; i < (s / 2); i++) {
        // extract bit on the left, from MSB
        p = s - i - 1;
        x = num & (1 << p);
        x = x >> p;
        printf("x: %d\n", x);

        // extract bit on the right, from LSB
        y = num & (1 << i);
        y = y >> i;
        printf("y: %d\n", y);

        var = var | (x << i);       // apply x
        var = var | (y << p);       // apply y
    }

    printf("new: 0x%x\n", new);

প্রশ্নটি "সর্বাধিক দক্ষ" জন্য জিজ্ঞাসা করা হয়েছিল, "সহজ / সরল" নয় not
পিটার কর্ডেস

1

নিম্নলিখিতগুলি সম্পর্কে কীভাবে:

    uint reverseMSBToLSB32ui(uint input)
    {
        uint output = 0x00000000;
        uint toANDVar = 0;
        int places = 0;

        for (int i = 1; i < 32; i++)
        {
            places = (32 - i);
            toANDVar = (uint)(1 << places);
            output |= (uint)(input & (toANDVar)) >> places;

        }


        return output;
    }

ছোট এবং সহজ (যদিও 32 বিট শুধুমাত্র)।


প্রশ্নটি "সবচেয়ে দক্ষ" জন্য জিজ্ঞাসা করা হয়েছিল; আমরা 32 বার লুপিংকে বাতিল করতে পারি। (এবং বিশেষত মুখোশ বদলানোর পাশাপাশি ফলটি এলএসবিতে নামাতে হবে না)
পিটার কর্ডেস

1

আমি ভাবলাম বিটটি বিপরীত করার একটি সহজ উপায়। এই যুক্তিতে কোনও ত্রুটি আছে কিনা দয়া করে আমাকে জানান। মূলত এই যুক্তিতে, আমরা অবস্থানের বিটের মান পরীক্ষা করি। বিপরীত অবস্থানে মান 1 হলে বিটটি সেট করুন।

void bit_reverse(ui32 *data)
{
  ui32 temp = 0;    
  ui32 i, bit_len;    
  {    
   for(i = 0, bit_len = 31; i <= bit_len; i++)   
   {    
    temp |= (*data & 1 << i)? (1 << bit_len-i) : 0;    
   }    
   *data = temp;    
  }    
  return;    
}    

প্রশ্নটি "সর্বাধিক দক্ষ" জন্য জিজ্ঞাসা করা হয়েছিল, "সহজ / সরল" নয় not
পিটার কর্ডেস

0
unsigned char ReverseBits(unsigned char data)
{
    unsigned char k = 0, rev = 0;

    unsigned char n = data;

    while(n)

    {
        k = n & (~(n - 1));
        n &= (n - 1);
        rev |= (128 / k);
    }
    return rev;
}

আকর্ষণীয়, কিন্তু একটি রানটাইম ভেরিয়েবল দ্বারা বিভাজন ধীর। kসর্বদা 2 এর শক্তি, তবে সংকলকরা সম্ভবত এটি প্রমাণ করে না এবং এটি বিট-স্ক্যান / শিফটে রূপান্তরিত করে।
পিটার কর্ডেস

0

আমি জানি যে আমি জানি সবচেয়ে সহজ পদ্ধতি অনুসরণ করে। MSBইনপুট এবং LSB'বিপরীত' আউটপুট:

unsigned char rev(char MSB) {
    unsigned char LSB=0;  // for output
    _FOR(i,0,8) {
        LSB= LSB << 1;
        if(MSB&1) LSB = LSB | 1;
        MSB= MSB >> 1;
    }
    return LSB;
}

//    It works by rotating bytes in opposite directions. 
//    Just repeat for each byte.

0
// Purpose: to reverse bits in an unsigned short integer 
// Input: an unsigned short integer whose bits are to be reversed
// Output: an unsigned short integer with the reversed bits of the input one
unsigned short ReverseBits( unsigned short a )
{
     // declare and initialize number of bits in the unsigned short integer
     const char num_bits = sizeof(a) * CHAR_BIT;

     // declare and initialize bitset representation of integer a
     bitset<num_bits> bitset_a(a);          

     // declare and initialize bitset representation of integer b (0000000000000000)
     bitset<num_bits> bitset_b(0);                  

     // declare and initialize bitset representation of mask (0000000000000001)
     bitset<num_bits> mask(1);          

     for ( char i = 0; i < num_bits; ++i )
     {
          bitset_b = (bitset_b << 1) | bitset_a & mask;
          bitset_a >>= 1;
     }

     return (unsigned short) bitset_b.to_ulong();
}

void PrintBits( unsigned short a )
{
     // declare and initialize bitset representation of a
     bitset<sizeof(a) * CHAR_BIT> bitset(a);

     // print out bits
     cout << bitset << endl;
}


// Testing the functionality of the code

int main ()
{
     unsigned short a = 17, b;

     cout << "Original: "; 
     PrintBits(a);

     b = ReverseBits( a );

     cout << "Reversed: ";
     PrintBits(b);
}

// Output:
Original: 0000000000010001
Reversed: 1000100000000000

0

আর একটি লুপ-ভিত্তিক সমাধান যা সংখ্যা কম হলে দ্রুত বের হয় (একাধিক ধরণের জন্য সি ++ এ)

template<class T>
T reverse_bits(T in) {
    T bit = static_cast<T>(1) << (sizeof(T) * 8 - 1);
    T out;

    for (out = 0; bit && in; bit >>= 1, in >>= 1) {
        if (in & 1) {
            out |= bit;
        }
    }
    return out;
}

অথবা সি তে স্বাক্ষরযুক্ত স্বাক্ষরের জন্য নয়

unsigned int reverse_bits(unsigned int in) {
    unsigned int bit = 1u << (sizeof(T) * 8 - 1);
    unsigned int out;

    for (out = 0; bit && in; bit >>= 1, in >>= 1) {
        if (in & 1)
            out |= bit;
    }
    return out;
}

0

দেখে মনে হচ্ছে আরও অনেকগুলি পোস্ট গতির বিষয়ে উদ্বিগ্ন (যেমন সেরা = দ্রুত)। সরলতার কী হবে? বিবেচনা:

char ReverseBits(char character) {
    char reversed_character = 0;
    for (int i = 0; i < 8; i++) {
        char ith_bit = (c >> i) & 1;
        reversed_character |= (ith_bit << (sizeof(char) - 1 - i));
    }
    return reversed_character;
}

এবং আশা করি যে চতুর সংকলকটি আপনার জন্য অনুকূলিত হবে।

আপনি যদি বিটগুলির একটি দীর্ঘ তালিকা বিট করতে চান ( sizeof(char) * nবিটগুলি সহ), আপনি এই ফাংশনটি পেতে ব্যবহার করতে পারেন:

void ReverseNumber(char* number, int bit_count_in_number) {
    int bytes_occupied = bit_count_in_number / sizeof(char);      

    // first reverse bytes
    for (int i = 0; i <= (bytes_occupied / 2); i++) {
        swap(long_number[i], long_number[n - i]);
    }

    // then reverse bits of each individual byte
    for (int i = 0; i < bytes_occupied; i++) {
         long_number[i] = ReverseBits(long_number[i]);
    }
}

এটি [10000000, 10101010] [01010101, 00000001] এ বিপরীত হবে।


আপনার অভ্যন্তরের লুপে 3 শিফট রয়েছে। সাথে একটি সংরক্ষণ করুন ith_bit = (c >> i) & 1reversed_charবিটটি স্থানান্তরিত করার পরিবর্তে স্থানান্তরিত করে একটি এসইউবি সংরক্ষণ করুন , যদি না আপনি আশা করছেন যে এটি গন্তব্য রেজিস্টারে নবম বিট সেট করার জন্য x86 থেকে sub something/ সংকলন করবে bts reg,reg
পিটার কর্ডেস

-1

সিউডো কোডে বিট বিপরীত

উত্স -> বাইটটি বিপরীত করতে হবে b00101100 গন্তব্য -> বিপরীতমুখী, স্বাক্ষরবিহীন প্রকারেরও হওয়া দরকার তাই সাইন বিটটি প্রস্তাব করা হয় না

টেম্পে অনুলিপি করা হয়েছে যাতে আসলটি প্রভাবিত হয় না, স্বাক্ষরবিহীন প্রকারেরও হওয়া দরকার যাতে সাইন বিটটি স্বয়ংক্রিয়ভাবে স্থানান্তরিত না হয়

bytecopy = b0010110

LOOP8: // বাইটোকপি <0 (negativeণাত্মক) হলে এটি 8 বার পরীক্ষা করুন

    set bit8 (msb) of reversed = reversed | b10000000 

else do not set bit8

shift bytecopy left 1 place
bytecopy = bytecopy << 1 = b0101100 result

shift result right 1 place
reversed = reversed >> 1 = b00000000
8 times no then up^ LOOP8
8 times yes then done.

-1

আমার সহজ সমাধান

BitReverse(IN)
    OUT = 0x00;
    R = 1;      // Right mask   ...0000.0001
    L = 0;      // Left mask    1000.0000...
    L = ~0; 
    L = ~(i >> 1);
    int size = sizeof(IN) * 4;  // bit size

    while(size--){
        if(IN & L) OUT = OUT | R; // start from MSB  1000.xxxx
        if(IN & R) OUT = OUT | L; // start from LSB  xxxx.0001
        L = L >> 1;
        R = R << 1; 
    }
    return OUT;

1
কি i? এছাড়াও, সেই ম্যাজিক ধ্রুবকটি * 4কী? এটা কি CHAR_BIT / 2?
পিটার কর্ডেস

-1

এটি 32 বিটের জন্য, যদি আমরা 8 টি বিট বিবেচনা করি তবে আকারটি পরিবর্তন করতে হবে।

    void bitReverse(int num)
    {
        int num_reverse = 0;
        int size = (sizeof(int)*8) -1;
        int i=0,j=0;
        for(i=0,j=size;i<=size,j>=0;i++,j--)
        {
            if((num >> i)&1)
            {
                num_reverse = (num_reverse | (1<<j));
            }
        }
        printf("\n rev num = %d\n",num_reverse);
    }

এলএসবি-> এমএসবি অর্ডারে ইনপুট পূর্ণসংখ্যা "নাম" পড়া এবং এমএসবি-> এলএসবি অর্ডারে num_revers এ সঞ্চয় করা।


1
আপনার কোডটিতে একটি ব্যাখ্যা যুক্ত করা উচিত যাতে এটি আরও সহজ বোঝা যায়।
টুনাকি

-3
int bit_reverse(int w, int bits)
{
    int r = 0;
    for (int i = 0; i < bits; i++)
    {
        int bit = (w & (1 << i)) >> i;
        r |= bit << (bits - i - 1);
    }
    return r;
}

3
সাধারণত, উত্তরগুলি আরও কার্যকর হয় যদি সেগুলিতে কোডটি কী করা উচিত এবং কেন এটি সমস্যার সমাধান করে তার ব্যাখ্যা অন্তর্ভুক্ত করে।
আইকনাগ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.