Từ 1 tới 2 trên tổng số 2 kết quả

Đề tài: Một vài macro hữu ích khi làm việc với bit

  1. #1
    Ngày gia nhập
    04 2010
    Nơi ở
    Thâm sơn cùng cốc
    Bài viết
    825

    Mặc định Một vài macro hữu ích khi làm việc với bit

    Trong C/C++ đôi khi các bạn cần làm việc với từng bit thường các thao tác đó thường là như sau:

    1. Lấy từ 1 dữ liệu x ( kiểu int,unsigned int, unsigned short,unsigned char) ra k bits bắt đầu từ vị trí bit thứ npos.
    2. Bật k bit trong 1 dữ liệu x
    3. Xóa k bit trong dữ liệu x
    4. Lấy k bit có trọng số thấp nhất
    5. Lấy k bit có trọng số cao nhất
    6. Lấy k bit từ vị trí bit thứ npos

    Đối với các thao tác trên các bạn thường viết ở dạng hàm, ví dụ
    C Code:
    1.  
    2. unsigned char setBit(unsigned char byte,int npos, int k){
    3.  unsigned char value=byte;
    4.  unsigned char mask=1<<npos; //Dịch bit 1 tới vị trí npos
    5.  while (k>0){
    6.   value|=mask;
    7.   mask<<1; //Dịch mask thêm 1 vị trí bit nữa
    8.  }
    9.  return value;
    10. }

    Cài đặt trên có ưu điểm: Dễ hiểu
    Nhược điểm :
    1. Phụ thuộc vào kiểu dữ liệu truyền vào và trả về
    2. Tốc độ không tối ưu

    Nhược điểm 1 có thể khắc phục bằng sử dụng tính đa hình, viết mỗi hàm 1 kiểu dữ liệu (int, unsigned int), hoặc mềm dẻo hơn là sử dụng template trong C++ như sau

    C++ Code:
    1. template <class T>
    2. T setBit(T data,int npos, int k){
    3.  T value=data;
    4.  T mask=1<<npos; //Dịch bit 1 tới vị trí npos
    5.  while (k>0){
    6.   data|=mask;
    7.   mask<<1; //Dịch mask thêm 1 vị trí bit nữa
    8.  }
    9.  return value;
    10. }

    Nhược điểm 2 về mặt tốc độ vẫn chưa khắc phục được.

    Ở đây xin giới thiệu với các bạn một vài macro trong C khắc phục được cả 2 nhược và tính mềm dẻo, dễ sử dụng (bạn không cần để ý đến dữ liệu truyền vào) và đạt tốc độ rất cao vì sử dụng toàn toán tử bit. Tốc độ đạt 1 tỷ phép toán bit trong vòng chưa đầy 1 mili second (Intel Core i3)

    C Code:
    1. /* =========== Macro by Tadius =================*/
    2.  
    3. #define SIZE_BITS_OF(x) (sizeof(x)<<3)
    4. #define SET_BITS_OF(byte,npos,numBits) (byte|(~((byte^~byte)<<numBits)<<npos))
    5. #define UNSET_BITS_OF(byte,npos,numBits) (byte&~(~((byte^~byte)<<numBits)<<npos))
    6. #define RANGE_BITS(byte,npos,numBits) ((byte&(~((byte^~byte)<<numBits)<<npos))>>npos)
    7. #define LEAST_BITS_OF(byte,numBits) RANGE_BITS(byte,0,numBits)
    8. #define MOST_BITS_OF(byte,numBits)  RANGE_BITS(byte,SIZE_BITS_OF(byte)-numBits,numBits)

    ================== Giải thích ======================
    1. Để lấy dược 1 dãy numBits bit trong biến X có độ dài n bit-length từ vị trí npos ta cần tạo mặt nạ mask, mask này phải có cùng độ dài n bit-length. Nhưng ở vị trí bit thứ [npos...npos+numBits ] thì toàn là bit 1, các bit còn lại là 0.

    Đầu tiên ta tạo ra một mask có độ dài n-bit length nhưng toàn là bit 1 như sau
    mask = (X^~X)
    Toán tử nghịch đảo bit ~ để đảo toàn bộ bit 0 thành 1 và 1 thành 0 trong X, khi đó ở cùng 1 vị trí bit tương ứng thì X và ~X là 2 bit trái ngược nhau. Lúc đó sử dụng toán tử xor ^ hoặc or | bit ta có được 1 mask toàn là bit 1.

    Ví dụ X=1011,0010 thì ~X=0100,1101 và mask=X^~X = 1111,1111

    2. Ta tạo ra numBits bit 0 bằng cách dịch bit của mask qua trái numBits
    mask = mask<<numBits; //Ta sẽ có numBits là bit 0 ở vị trí bit thấp nhất của Mask
    Giả sử numBits =3
    mask = 0xEF(1110,1111b) <<3; thì mask = 0xF8 (1111,1000b)
    3. Đảo bit mask ta có được
    mask= ~mask = 0x07 (0000,0111b)
    4. Dịch npos bit qua bên trái
    mask= mask<<npos; với npos= 2 ta có
    mask= 0x07<<2 (0000,0111b<<2) = (0001,1100b)

    5. Vậy là ta đã tạo được Mask từ bit thứ 2 đến bit thứ 2+3 = 5 là toàn bit 1.
    Việc còn lại đơn giản là mask&X là sẽ lấy được 3 bit tương ứng, là 000[1,00]00 ở giá trị ban đầu của X là 1011,0010.

    6.Bước cuối dịch lại sang phải npos bit nữa là sẽ có
    000[1,00]00b >> 2 = 0000,0100b = 4

    Các mã còn lại các bạn có thể tự ngâm cứu thêm Set/Unset bit.
    Nếu các bạn có cải tiến tốt hơn về mặt tốc độ xin hãy cùng thảo luận

  2. #2
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,750

    Góp ý chút: Nên để một khoảng trắng giữa các operators với các biến

    Để set 1 bit, có thể sử dụng OR ví dụ với một kiểu dữ liệu 8 bit (1 byte):
    number = number | 8; //thiết lập bit thứ 4 là 1, (8 == 00001000). Áp dụng cho vấn đề trên sẽ là: number |= 1 << nBit;
    number = number & 247; //xóa bit thứ 4, (247 == 11110111). Áp dụng cho vấn đề trên sẽ là: number &= ~(1 << nBit);

    Ứng dụng của các toán tử xử lý trên từng bit rất nhiều, điển hình và phổ biến đó là việc xây dựng license cho phần mềm hoặc phân quyền!
    Email: admin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667 (Office: 04 6329 2380)
    Yahoo & Skype: dreaminess_world (Vui lòng chỉ rõ mục đích ngay khi liên hệ, cảm ơn!)

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó. Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp!

Các đề tài tương tự

  1. Lập trình C++ Tại sao dùng Macro
    Gửi bởi ducthanh150792 trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 22
    Bài viết cuối: 20-01-2012, 07:04 PM
  2. Macro.
    Gửi bởi biennhatrang trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 1
    Bài viết cuối: 05-10-2011, 12:46 PM
  3. Kỹ thuật C++ Tại sao không dùng được macro?
    Gửi bởi hquy trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 23
    Bài viết cuối: 12-09-2010, 03:35 PM
  4. Sử dụng MACRO trong ASM
    Gửi bởi trần trân trong diễn đàn Thắc mắc lập trình Visual C++
    Trả lời: 0
    Bài viết cuối: 01-01-2010, 09:55 AM
  5. [C/C++] lệnh gộp MACRO???
    Gửi bởi Nhuan_Trang_Only_Love trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 5
    Bài viết cuối: 06-02-2007, 05:33 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn