Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 1 của 2 12 CuốiCuối
Kết quả 1 đến 10 của 15
  1. #1
    Ngày tham gia
    Feb 2014
    Bài viết
    0

    Một số về bitwise operators

    Một số chú ý về ' Bitwise Operator '
    ----------------------------------------------------
    Các phép toán trên bit :
    _bitwise AND ( & )
    _bitwise OR ( | )
    _bitwise XOR ( ^ )
    _bitwise NOT ( ~ )
    _left shift ( << )
    _right shift ( >> )

    Tóm tắt một chút :
    1. Bitwise AND ( & )
    Chú ý đây là phép toán chỉ áp dụng trên bit cần phân biệt với &&, đây là so sánh toán tử điều kiện
    Bảng giá trị :
    0 & 0 = 0 : 1 & 0 = 0 : 0 & 1 = 0 : 1 & 1 = 1
    Ví dụ : 01101111 & 11110000 = 01100000
    So sánh AND ( & ) từng bit tương ứng ( cùng vị trí hay vị trí tương ứng trong byte )
    Thêm một ví dụ khác :
    $result = 124 & 99;
    Chuyển sang hệ BIN, nhị phân.
    124D = 01111100B
    99D = 01100011B
    D = Decimal : Hệ thập phân (base-10)
    B = Binary : Hệ nhị phân (base-2)
    So sánh từng vị trí bit trong byte theo AND ( & ) thu được
    $result = 96 ( = 01100000B)

    2.Các toán tử khác OR , XOR , NOT :
    OR ( | ) : Bảng giá trị :
    0 | 0 = 0 : 0 | 1 = 1 : 1 | 0 = 1 : 1 | 1 = 1
    XOR ( ^ ) : Bảng giá trị :
    0 ^ 0 = 0 : 0 ^ 1 = 1 : 1 ^ 0 = 1 : 1 ^ 1 = 0
    NOT ( ~ ) :
    ~1 = 0 : ~0 = 1

    3.Hai phép dịch bit : left-shift và right-shift :
    Ví dụ :
    $result = $x >> 1 ;
    mang ý nghĩa : các bit của $x dịch sang phải 1 bit. <hơi khó hiểu>.
    Cụ thể :
    $result = 99 >> 1 ;
    mang ý nghĩa : các bit của 99 dich sang phải 1 bit.
    Từ từ thực hiện :
    chuyển sang hệ nhị phân (binary) : 99D = 01100011B [X]
    dịch sang phải 1 bit tức là : 00110001 [Y]
    So sánh 2 số tại [X] và [Y] để ý thấy :
    từ [X] sang [Y] : bit cuối cùng biến mất và thêm vào đầu là 0 thay thế bit vị trí đầu tiên.
    Có thể hiểu đơn giản : là xóa bit cuối cùng đi và lấp đầy khoảng trống ( thêm 0 vào đầu bit )
    Kết quả : $result = 49 ( = 00110001B )
    Tổng quát hơn : $result = $x >> n ;
    mang ý nghĩa : dịch các bit của $x sang phải n bit ( = n vị trí ), thay thể các vị trí trống = 0
    Các ví dụ trên dùng số nguyên 8-bit.
    Với các bit lớn hơn 16-bit, 32-bit tương tự bạn chỉ cần thêm 0 cho đủ số bit tương ứng.
    Một điều chắc chắn là : giả sử $x là số nguyên k-bit thì khi $x >> n với n >= k kết quả thu được luôn là 0.

    Chú ý khác :
    1). Để ý ví dụ sau :
    $x = 17 >> 1;
    $y = 16 >> 1;
    So sánh $x và $y ?
    17D = 00010001B;
    16D = 00010000B;
    Ái dà : kết quả thu được $x = $y = 8;
    --> Cái này hay nhỉ [IMG]images/smilies/biggrin.png[/IMG]

    2). Không nên dịch bit quá lớn, vượt quá giới hạn cho phép.
    Giả sử bạn dùng 16-bit với phép tính : $result = 35000 << 1;
    kết quả tính ra thu được 70000 , nghĩ là thế nhưng thực tế là lỗi
    vì giới hạn 16-bit max = 65536.

    3). Dịch bit và Lũy Thừa cơ số 2 : [IMG]images/smilies/biggrin.png[/IMG]
    so sánh 2 cái này phát :
    $x = 99 >> 1;
    $y = 99 /2;
    Kết quả : $x = $y = 49 ; bằng nhau
    làm phép tính khác ;
    $x = 99 << 1;
    $y = 99 * 2;
    Kết quả : $x = $y = 198; bằng nhau

    Tóm lại có được quy luật chuyển bit [IMG]images/smilies/biggrin.png[/IMG]
    _Dịch sang trái n bit với n là số nguyên dương thì tương đương với nhân với 2 lũy thừa n
    _Dịch sang phải n bit với n là số nguyên dương thì tương đương với chia với 2 lũy thừa n

    Thành ra dùng quy tắc chuyển dịch trên nhanh hơn cứ ngồi convert rồi dịch bit [IMG]images/smilies/biggrin.png[/IMG]
    Kiến thức nho nhỏ, viết lại chia sẻ chút ^_^!

    Written by Pete

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    !!^_^!! Lâu lâu post 1 bài ra trò đấy [IMG]images/smilies/biggrin.png[/IMG],


    _Dịch sang trái n bit với n là số nguyên dương thì tương đương với nhân với 2 lũy thừa n
    _Dịch sang phải n bit với n là số nguyên dương thì tương đương với chia với 2 lũy thừa n
    Đôi khi lối suy nghĩ đơn giản lại giúp ích, lúc học hợp ngữ, tớ cũng ghét ba cái vụ dịch chuyển bit này lắm, nhưng nhờ nghĩ đơn giản như vậy nên .... [IMG]images/smilies/applause.gif[/IMG]

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Cám ơn bác Xcross87 nhé. Em đang tìm hiểu cái này coi bài của bác thì ko thể chê vào đâu được.

  4. #4
    Nói về bitwise là người ta thường nhắc đến số nguyên dương chứ có phải mấy trường hợp của các bác đâu trời -_-;;

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trường hợp 1 của tui là nguyên dương đó chớ. Và ứng dụng của tui cũng đòi phải làm vậy đó chớ. (1 << 32 = 1!!!).
    Mới thử lại bên g++, nó cho 1 warning và cũng cho ra 1 << 32 = 1 (nhưng (1 << 16) << 16 thì đúng = 0 ^^).

  6. #6
    Trích dẫn Gửi bởi hieusua
    Trường hợp 1 của tui là nguyên dương đó chớ. Và ứng dụng của tui cũng đòi phải làm vậy đó chớ. (1 << 32 = 1!!!).
    Mới thử lại bên g++, nó cho 1 warning và cũng cho ra 1 << 32 = 1 (nhưng (1 << 16) << 16 thì đúng = 0 ^^).
    Này, tôi không biết cậu giỏi thế nào chứ. Cậu đọc hết từng chữ của bài tôi viết chưa ???
    - Đọc cái chú ý 2: giời hạn dịch bit [MỞ MẮT CHO TO RA RỒI ĐỌC]
    - Bài này tôi để TITLE là "MỘT SỐ VỀ BITWISE" chứ không phải TẤT CẢ VỀ BITWISE

    Nếu cậu giỏi, thích văn vẹo người khác thì sao không làm hẳn một bài hướng dẫn chia sẻ mọi người đi.

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trước tiên, xin lỗi vì mấy bài post kia làm bạn nổi nóng. Nhưng mình không thích vặn vẹo người khác kiểu này (nhất là với những bạn nhiệt tình - bạn review lại các post của mình sẽ thấy). Thiệt tình, tại diễn đàn không có nút Thanks, chứ không mình đã Thanks bạn trước khi post mấy post kia thì chắc bạn không hiểu lầm vậy.

    Số nguyên âm thì mình hoàn toàn đồng ý là nó ít khi được làm việc với các toán tử xử lý bit.
    Còn trường hợp kia, vì cái mình làm cũng có dính nhiều tới bitwise, nên mình hay gặp nó, và chưa giải thích được vì sao nó thế, chỉ định post lên và hỏi bạn (và mấy bạn khác) xem vì sao thôi mà (với lại để mấy bạn khác lưu ý về trường hợp đặc biệt này). Và mình cũng xin lỗi vì cái ví dụ mình đưa ra là SAI. Mình đặt lại vấn đề thế này:
    Mã:
    int a, b;
    a = 1;
    b = a >> 32;
    Vì mình rất thích bitwise, nên thay vì đem chia, mình thường xài phép dịch bit. Ở đây đáng lẽ ra "a >> 32" thì bằng "a / (2^32)", rõ ràng luôn = 0 (và không vi phạm cái giới hạn ở chú ý 2 bạn đưa ra). Mà tại sao nó vẫn là 1? g++ cho 1 warning: right shift count >= width of type. Mình nghĩ là khi right shift >= max bit của biến thì nó sẽ không dịch nữa, nhưng nếu vậy thì hơi củ chuối nhỉ?

  8. #8
    Trích dẫn Gửi bởi hieusua
    Trước tiên, xin lỗi vì mấy bài post kia làm bạn nổi nóng. Nhưng mình không thích vặn vẹo người khác kiểu này (nhất là với những bạn nhiệt tình - bạn review lại các post của mình sẽ thấy). Thiệt tình, tại diễn đàn không có nút Thanks, chứ không mình đã Thanks bạn trước khi post mấy post kia thì chắc bạn không hiểu lầm vậy.

    Số nguyên âm thì mình hoàn toàn đồng ý là nó ít khi được làm việc với các toán tử xử lý bit.
    Còn trường hợp kia, vì cái mình làm cũng có dính nhiều tới bitwise, nên mình hay gặp nó, và chưa giải thích được vì sao nó thế, chỉ định post lên và hỏi bạn (và mấy bạn khác) xem vì sao thôi mà (với lại để mấy bạn khác lưu ý về trường hợp đặc biệt này). Và mình cũng xin lỗi vì cái ví dụ mình đưa ra là SAI. Mình đặt lại vấn đề thế này:
    Mã:
    int a, b;
    a = 1;
    b = a >> 32;
    Vì mình rất thích bitwise, nên thay vì đem chia, mình thường xài phép dịch bit. Ở đây đáng lẽ ra "a >> 32" thì bằng "a / (2^32)", rõ ràng luôn = 0 (và không vi phạm cái giới hạn ở chú ý 2 bạn đưa ra). Mà tại sao nó vẫn là 1? g++ cho 1 warning: right shift count >= width of type. Mình nghĩ là khi right shift >= max bit của biến thì nó sẽ không dịch nữa, nhưng nếu vậy thì hơi củ chuối nhỉ?
    biến kiểu int trong g++ là 4 bytes (32 bit) => right shift tối đa là 31 nháy.
    Bạn thử cho nó dịch phải 31 nháy và 1 nháy xem nó ra bao nhiêu...

    Tớ test thử:

    Mã:
    #include <stdio.h> int main(void){    int a, b;    a = 1;        b = a >> 1;    printf("1 bit:\t b = %d 
    ", b);        b = a >> 2;    printf("2 bit:\t b = %d 
    ", b);     b = a >> 31;    printf("31 bit:\t b = %d 
    ", b);     b = a >> 32;    printf("32 bit:\t b = %d 
    ", b);     b = a >> 33;    printf("33 bit:\t b = %d 
    ", b);     return 1;}
    Kết quả:

    Mã:
    1 bit:   b = 02 bit:   b = 031 bit:  b = 032 bit:  b = 133 bit:  b = 0Press any key to continue . . .
    Thử lại với giá trị khác: lấy a = 3: thì kết quả là:
    Mã:
    1 bit:   b = 1
    2 bit:   b = 0
    31 bit:  b = 0
    32 bit:  b = 3
    33 bit:  b = 1
    Press any key to continue . . .
    Thay với bất kì giá trị nào của a cũng đều thế này.

    Đưa ra kết luận:

    + Nếu giới hạn dịch vượt quá kích thước của kiểu dữ liệu thì phép dịch sẽ bị luân hồi, tức là dịch lại từ đâu.

    Ví dụ: kiểu int = 4 bytes = 32 bits => dịch tối đa 31 nháy (0->31). Từ 32 trở lại nó sẽ dịch ngược lại từ đầu tức là: a >> 0 == a >> 32; a >> 1 == a >> 33 .... (==: kí hiệu tương đương).

    Test thử sẽ rõ:

    Mã:
    #include <stdio.h> int main(void){    char a = 13;        if((a >> 1) == (a >> 33))        printf("TRUE 
    ");     return 1;}
    OK?

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    ps hieusua : Một thắc mắc, cậu không hiểu int có 1 bit cuối là âm hay dương làm sao cậu viết ra đoạn code này nhỉ ?

    Mã:
    int abs(int in) {    return ((in ^ 0xffffffff) + 1);}

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    @X: Hiểu rùi. Có lẽ do môi trường 32 bit nên nó không cho dịch quá 32 bit.
    Câu lệnh:
    a << b ; a >> b;
    Sẽ thành:
    a << (b % 32); a >> (b % 32);
    (Mình thử với kiểu char và short khi dịch quá 8 bit hay 16 bit đều ra 0 -> đúng).

    @r2: Mình post xong 1 lúc mới thấy sai, mà chưa kịp sửa :P

 

 
Trang 1 của 2 12 CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •