সংকলন সময়ে সিআরসি 32 টেবিলটি গণনা করুন [বন্ধ]


16

CRC32 এর রেফারেন্স বাস্তবায়ন একটি লুকআপ টেবিল নির্ণয় রানটাইম হয়:

/* Table of CRCs of all 8-bit messages. */
unsigned long crc_table[256];

/* Flag: has the table been computed? Initially false. */
int crc_table_computed = 0;

/* Make the table for a fast CRC. */
void make_crc_table(void)
{
    unsigned long c;

    int n, k;
    for (n = 0; n < 256; n++) {
        c = (unsigned long) n;
        for (k = 0; k < 8; k++) {
            if (c & 1) {
                c = 0xedb88320L ^ (c >> 1);
            } else {
                c = c >> 1;
            }
        }
        crc_table[n] = c;
    }
    crc_table_computed = 1;
}

আপনি কি সংকলন-সময় টেবিলটি গণনা করতে পারেন, এভাবে ফাংশন এবং স্থিতির পতাকা থেকে মুক্তি পেয়ে চলেছেন?


2
এখানে উদ্দেশ্য প্রাথমিক বিজয়ী মানদণ্ডটি কী?
জন ডিভোরাক

এছাড়াও, ভাষা নির্দিষ্ট প্রশ্নগুলি এখানে ভ্রান্ত হয়। আপনার সি ++ ট্যাগটি সরানো উচিত।
গর্বিত হাসেলেলার 18

উত্তর:


12

এখানে একটি সরল সি সমাধান রয়েছে:

crc32table.c

#if __COUNTER__ == 0

    /* Initial setup */
    #define STEP(c) ((c)>>1 ^ ((c)&1 ? 0xedb88320L : 0))
    #define CRC(n) STEP(STEP(STEP(STEP(STEP(STEP(STEP(STEP((unsigned long)(n)))))))))
    #define CRC4(n) CRC(n), CRC(n+1), CRC(n+2), CRC(n+3)

    /* Open up crc_table; subsequent iterations will fill its members. */
    const unsigned long crc_table[256] = {

    /* Include recursively for next iteration. */
    #include "crc32table.c"

#elif __COUNTER__ < 256 * 3 / 4

    /* Fill the next four CRC entries. */
    CRC4((__COUNTER__ - 3) / 3 * 4),

    /* Include recursively for next iteration. */
    #include "crc32table.c"

#else

    /* Close crc_table. */
    };

#endif

এটি নন-স্ট্যান্ডার্ড __COUNTER__ম্যাক্রোর পাশাপাশি __COUNTER__ম্যাক্রোর আর্গুমেন্ট হিসাবে পাস করার আগে একটি মূল্যায়ন শব্দার্থবিজ্ঞানের উপর নির্ভর করে ।

নোট করুন, যেহেতু STEPতার যুক্তিটি দু'বার মূল্যায়ন করেছে এবং এটির CRCআটটি নেস্টেড আহ্বানগুলি ব্যবহার করে, কোড আকারে একটি ছোট সংযুক্তি বিস্ফোরণ ঘটেছে:

$ cpp crc32table.c | wc -c
4563276

আমি এটি 32-বিট লিনাক্সে জিসিসি 4.6.0 এবং ক্ল্যাং 2.8 এ পরীক্ষা করেছি এবং উভয়ই সঠিক টেবিল তৈরি করে।


দুর্দান্ত, আমি অবশ্যই এটি আশা করছিলাম না। একটি +1 আছে।
আর মার্টিনহো ফার্নান্দিস

9

মূল লুপ

for (k = 0; k < 8; k++) {
    if (c & 1) {
        c = 0xedb88320L ^ (c >> 1);
    } else {
        c = c >> 1;
    }
}

একটি মেটা ফাংশনে রূপান্তর করা যায়:

template <unsigned c, int k = 8>
struct f : f<((c & 1) ? 0xedb88320 : 0) ^ (c >> 1), k - 1> {};

template <unsigned c>
struct f<c, 0>
{
    enum { value = c };
};

তারপরে, এই মেটা-ফাংশনে 256 টি কল (অ্যারের প্রারম্ভক হিসাবে) প্রিপ্রসেসর দ্বারা উত্পাদিত হয়:

#define A(x) B(x) B(x + 128)
#define B(x) C(x) C(x +  64)
#define C(x) D(x) D(x +  32)
#define D(x) E(x) E(x +  16)
#define E(x) F(x) F(x +   8)
#define F(x) G(x) G(x +   4)
#define G(x) H(x) H(x +   2)
#define H(x) I(x) I(x +   1)
#define I(x) f<x>::value ,

unsigned crc_table[] = { A(0) };

আপনি যদি বুস্ট ইনস্টল করে থাকেন তবে অ্যারে ইনিশিয়ালাইজার তৈরি করা কিছুটা সহজ a

#include <boost/preprocessor/repetition/enum.hpp>

#define F(Z, N, _) f<N>::value

unsigned crc_table[] = { BOOST_PP_ENUM(256, F, _) };

অবশেষে, নিম্নলিখিত পরীক্ষামূলক ড্রাইভারটি কনসোলে সমস্ত অ্যারে উপাদানগুলি কেবল মুদ্রণ করে:

#include <cstdio>

int main()
{
    for (int i = 0; i < 256; ++i)
    {
        printf("%08x  ", crc_table[i]);
    }
}

6

একটি সি ++ 0x সমাধান

template<unsigned long C, int K = 0>
struct computek {
  static unsigned long const value = 
    computek<(C & 1) ? (0xedb88320L ^ (C >> 1)) : (C >> 1), K+1>::value;
};

template<unsigned long C>
struct computek<C, 8> {
  static unsigned long const value = C;
};

template<int N = 0, unsigned long ...D>
struct compute : compute<N+1, D..., computek<N>::value> 
{ };

template<unsigned long ...D>
struct compute<256, D...> {
  static unsigned long const crc_table[sizeof...(D)];
};

template<unsigned long...D>
unsigned long const compute<256, D...>::crc_table[sizeof...(D)] = { 
  D...
};

/* print it */
#include <iostream>

int main() {
  for(int i = 0; i < 256; i++)
    std::cout << compute<>::crc_table[i] << std::endl;
}

জিসিসি (4.6.1) এবং কলং (ট্রাঙ্ক 134121) এ কাজ করে।


সম্পর্কিত C >> 1, নেতিবাচক মানগুলি সঠিক অনির্দিষ্ট আচরণে স্থানান্তর করছে না? ;)
ফ্রেডওভারফ্লো

এছাড়াও, আপনি যে অংশটি অ্যারে সংজ্ঞায়িত করেছেন সেই অংশটি কি ব্যাখ্যা করতে পারবেন? আমি সেখানে কিছুটা হারিয়েছি ...
ফ্রেডওভারফ্লো

@ ফ্রেড আপনি ঠিক বলেছেন। আমিও করাব Cএকটি unsigned long। ধ্রুবক অ্যারেটি প্যাক সম্প্রসারণের মাধ্যমে সূচনা করার জন্য সংজ্ঞায়িত করা হয় D...Dএকটি নন-টাইপ টেম্পলেট প্যারামিটার প্যাক। একবার জিসিসি এটি সমর্থন করে, কেউ এর সাথে শ্রেণীর অ্যারেও ঘোষণা করতে পারে static unsigned long constexpr crc_table[] = { D... };, তবে জিসিসি এখনও ব্রেসড ইন-ক্লাস ইনিশিয়ালাইজারদের বিশ্লেষণ করে না। সুবিধাটি compute<>::crc_table[I]হ'ল পরে কোডটিতে ধ্রুবক প্রকাশের মধ্যে ব্যবহার করা যেতে পারে।
জোহানেস স্কাউব -

5

সি ++ 0x সহ constexpr। GCC4.6.1 এ কাজ করে

constexpr unsigned long computek(unsigned long c, int k = 0) {
  return k < 8 ? computek((c & 1) ? (0xedb88320L ^ (c >> 1)) : (c >> 1), k+1) : c;
}

struct table {
  unsigned long data[256];
};

template<bool> struct sfinae { typedef table type; };
template<> struct sfinae<false> { };

template<typename ...T>
constexpr typename sfinae<sizeof...(T) == 256>::type compute(int n, T... t) { 
  return table {{ t... }}; 
}

template<typename ...T>
constexpr typename sfinae<sizeof...(T) <= 255>::type compute(int n, T... t) {
  return compute(n+1, t..., computek(n));
}

constexpr table crc_table = compute(0);

#include <iostream>

int main() {
  for(int i = 0; i < 256; i++)
    std::cout << crc_table.data[i] << std::endl;
}

তারপরে আপনি crc_table.data[X]সংকলন সময়ে ব্যবহার করতে পারেন কারণ crc_tableএটি constexpr


4

এটি আমার প্রথম রূপক :

#include <cassert>
#include <cstddef>

template <std::size_t N, template <unsigned long> class T, unsigned long In>
struct times : public T<times<N-1,T,In>::value> {};

template <unsigned long In, template <unsigned long> class T>
struct times<1,T,In> : public T<In> {};

template <unsigned long C>
struct iter {
    enum { value = C & 1 ? 0xedb88320L ^ (C >> 1) : (C >> 1) };
};

template <std::size_t N>
struct compute : public times<8,iter,N> {};

unsigned long crc_table[] = {
    compute<0>::value,
    compute<1>::value,
    compute<2>::value,
    // .
    // .
    // .
    compute<254>::value,
    compute<255>::value,
};

/* Reference Table of CRCs of all 8-bit messages. */
unsigned long reference_table[256];

/* Flag: has the table been computed? Initially false. */
int reference_table_computed = 0;

/* Make the table for a fast CRC. */
void make_reference_table(void)
{
    unsigned long c;

    int n, k;
    for (n = 0; n < 256; n++) {
        c = (unsigned long) n;
        for (k = 0; k < 8; k++) {
            if (c & 1) {
                c = 0xedb88320L ^ (c >> 1);
            } else {
                c = c >> 1;
            }
        }
        reference_table[n] = c;
    }
    reference_table_computed = 1;
}

int main() {
    make_reference_table();
    for(int i = 0; i < 256; ++i) {
        assert(crc_table[i] == reference_table[i]);
    }
}

আমি টেমপ্লেটে কলগুলি "হার্ডকড" করেছি যা গণনা করে :)


1
আপনি যদি সেভাবে এটি করতে যাচ্ছেন তবে আপনি কেন প্রোগ্রামটিতে আসল মানগুলি হার্ডকোড করবেন না? (অবশ্যই অন্য একটি পদ্ধতি দিয়ে এগুলি পাওয়ার পরে।) সংকলনের সময় সাশ্রয় করে।
ম্যাথু

পরীক্ষা এবং timesটেমপ্লেটের জন্য +1
ফ্রেডওভারফ্লো

@ ম্যাথিউ: কেবল সি ++ ০৩ এর সাথে খুব কম পছন্দ নেই। ফ্রেডের মতো আপনি প্রিপ্রসেসর ব্যবহার করতে পারেন তবে সংকলনের সময়টি ছোট করা হবে না। এবং স্পষ্টতই, তার প্রিপ্রোসেসর তার সমাধানটিতে চাপ দেয় :)
আর মার্টিনহো ফার্নান্দিস

@ ম্যাথজে বক্তব্যটি হ'ল সংকলনকালে আসলে এটি গণনা করা , তাদের হার্ডকোড না করা। ফ্রেডের উত্তর এই ফর্মের একটি অ্যারে উত্পন্ন unsigned crc_table[] = { f<0>::value , f<0 + 1>::value , f<0 + 2>::value , f<0 + 2 + 1>::value , f<0 + 4>::value , f<0 + 4 + 1>::value , f<0 + 4 + 2>::value , f<0 + 4 + 2 + 1>::value , f<0 + 8>::value ,করে : প্রিপ্রোসেসর ব্যবহার করে। আমার হিসাবে সংকলন করতে এটি প্রায় সময় নেয়। আপনি যদি চান তবে আপনি এই শেষ অনুচ্ছেদটি "আমি বাইরের লুপটি আনারোলড করেছি" হিসাবে পড়তে পারেন। সি ++ 03 তে
আর

আহ, আমি প্রশ্নের প্রয়োজনীয়তার দিকে যথেষ্ট মনোযোগ দিচ্ছিলাম না। +1, যদিও আমি নিশ্চিত না যে আমি আর প্রশ্নটি পছন্দ করি। আমি আমার কোডটিকে ব্যবহারিক চ্যালেঞ্জগুলি পছন্দ করি: পি
ম্যাথু

3

ডি

import std.stdio, std.conv;

string makeCRC32Table(string name){

  string result = "immutable uint[256]"~name~" = [ ";

  for(uint n; n < 256; n++){
    uint c = n;
    for(int k; k < 8; k++)
      c = (c & 1) ? 0xedb88320L ^ (c >> 1) : c >>1;
    result ~= to!string(c) ~ ", ";
  }
  return result ~ "];";
}

void main(){

  /* fill table during compilation */
  mixin(makeCRC32Table("crc_table"));

  /* print the table */
  foreach(c; crc_table)
    writeln(c);
}

এটি সত্যিই লজ্জার জন্য সি ++ রাখে, তাই না?


2
আসলে, আমি অ-স্ট্রাইলি-টাইপযুক্ত সমাধানগুলি পছন্দ করি। এটি দেখতে অনেকটা সংকলন-সময়ের মতো eval
আর মার্টিনহো ফার্নান্দেস

এর জন্য একটি স্ট্রিং মিক্সিন ব্যবহার করার দরকার নেই, এখানে আমরা কীভাবে ডি এর স্ট্যান্ডার্ড লাইব্রেরি, জেনেটেবলস এবং কল-সাইটে ফলাফল তথ্য বিভাগে ফলাফল সংরক্ষণ করতে পারি do
মার্টিন নওক

3

সি / সি ++, 306 295 বাইট

#define C(c)((c)>>1^((c)&1?0xEDB88320L:0))
#define K(c)(C(C(C(C(C(C(C(C(c))))))))),
#define F(h,l)K((h)|(l+0))K((h)|(l+1))K((h)|(l+2))K((h)|(l+3))
#define R(h)F(h<<4,0)F(h<<4,4)F(h<<4,8)F(h<<4,12)
unsigned long crc_table[]={R(0)R(1)R(2)R(3)R(4)R(5)R(6)R(7)R(8)R(9)R(10)R(11)R(12)R(13)R(14)R(15)};

বিপরীতে কাজ করে, আমরা crc_table নামের একটি স্বাক্ষরবিহীন দীর্ঘ অ্যারে দিয়ে শেষ করি না। আমরা অ্যারের আকার বাদ দিতে পারি কারণ ম্যাক্রোগুলি নিশ্চিত করবে যে অ্যারেতে ঠিক 256 উপাদান রয়েছে। আমরা ম্যাক্রো আর এর 16 টি আমন্ত্রণ ব্যবহার করে ডেটার 16 'সারি' দিয়ে অ্যারে শুরু করি।

আর এর প্রতিটি অনুরোধ চারটি ধ্রুবকের (ম্যাক্রো কে) চারটি টুকরো (ম্যাক্রো কে) এর মোট 16 টি কলামের ডেটাতে প্রসারিত হয়।

ম্যাক্রো কে হ'ল মূল প্রশ্ন থেকে কোডে কে দ্বারা তালিকাবদ্ধ তালিকাভুক্ত লুপ। এটি ম্যাক্রো সি-কে ডাক দিয়ে মান সিটিকে আটবার আপডেট করে

এই প্রিপ্রোসেসর ভিত্তিক সমাধানটি ম্যাক্রো প্রসারণের সময় বেশ কিছুটা স্মৃতি ব্যবহার করে। আমি ম্যাক্রো সম্প্রসারণের অতিরিক্ত স্তরের এবং আমার সংকলকটি ছুঁড়ে ফেলে এটিকে আরও ছোট করার চেষ্টা করেছি। উপরের কোডটি সিগুইনের (উইন্ডোজ 7 64 বিট 8 জিবি র‌্যাম) এর অধীনে ভিজ্যুয়াল সি ++ 2012 এবং জি ++ 4.5.3 উভয়ের সাথেই (ধীরে ধীরে) সংকলন করে।

সম্পাদনা:

উপরের খণ্ডটি সাদা স্থান সহ 295 বাইট। সি ব্যতীত সমস্ত ম্যাক্রোগুলি প্রসারিত করার পরে এটি বাড়িয়ে 9,918 বাইটে পরিণত হয়। সি ম্যাক্রোর প্রতিটি স্তরের প্রসারিত হওয়ার সাথে সাথে আকারটি দ্রুত বৃদ্ধি পায়:

  1. 25.182
  2. 54.174
  3. 109.086
  4. 212.766
  5. 407.838
  6. 773.406
  7. 1.455.390
  8. 2.721.054

সুতরাং সমস্ত ম্যাক্রোগুলি প্রসারিত হওয়ার পরে, সেই ছোট্ট 295 বাইট ফাইলটি 2.7 মেগাবাইটের বেশি কোডে প্রসারিত হবে যা মূল 1024 বাইট অ্যারে (32 বিট স্বাক্ষরবিহীন দীর্ঘ মান ধরে) সংগ্রহ করতে হবে!

অন্য সম্পাদনা:

অতিরিক্ত 11 বাইট আউট আটকানোর জন্য আমি অন্য উত্তর থেকে ম্যাক্রোর ভিত্তিতে সি ম্যাক্রো সংশোধন করেছি এবং পুরো প্রসারিত ম্যাক্রোর আকারকে হ্রাস করেছি। যদিও ২.7 এমবি 54 এমবি (সমস্ত ম্যাক্রো বিস্তারের আগের চূড়ান্ত আকার) এর মতো খারাপ নয়, এটি এখনও তাৎপর্যপূর্ণ।


এটি কোড-গল্ফ নয় , তাই আপনার চরিত্রের সংখ্যা ছোট করার দরকার নেই।
ইলমারি করোনেন

আহ। সুতরাং এটাই. আমার পক্ষে খারাপ। যদিও আমি মনে করি এই বাস্তবায়নটি পোর্টেবল (যার অর্থ এটি সি ভাষা এবং প্রিপ্রোসেসরকে মেনে চলে; এর প্রকৃত বহনযোগ্যতা ম্যাক্রো বিস্তারের উপর পরিবেশের সঠিক সীমাবদ্ধতার উপর নির্ভর করবে)।
কাসাডিরোবিসন

3

আমি শেষের তিনটি লাইনটি এর পরিবর্তে পূর্ববর্তী উত্তরটি সংশোধন করব:

#define crc4( x)    crcByte(x), crcByte(x+1), crcByte(x+2), crcByte(x+3)
#define crc16( x)   crc4(x), crc4(x+4), crc4(x+8), crc4(x+12)
#define crc64( x)   crc16(x), crc16(x+16), crc16(x+32), crc16(x+48)
#define crc256( x)  crc64(x), crc64(x+64), crc64(x+128), crc64(x+192)

যেখানে crcByte হ'ল তার কে ম্যাক্রো পিছনে কমা ছাড়াই। তারপরে টেবিলটি নিজেই তৈরি করুন:

static const unsigned long crc32Table[256] = { crc256( 0)};

আর অ্যারের আকারটি কখনই ছাড়বেন না কারণ সংকলক তখন যাচাই করবে যে আপনার কাছে সঠিক পরিমাণের উপাদান রয়েছে।

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