Vài ngày trước, thành viên StackExchange Anto đã hỏi về việc sử dụng hợp lệ cho các nhà khai thác bit-khôn ngoan. Tôi đã nói rằng dịch chuyển nhanh hơn nhân và chia số nguyên cho lũy thừa của hai. Thành viên của StackExchange, Daemin đã chống lại bằng cách tuyên bố rằng sự thay đổi bên phải có vấn đề với các số âm.
Vào thời điểm đó, tôi chưa bao giờ thực sự nghĩ về việc sử dụng các toán tử thay đổi với các số nguyên đã ký. Tôi chủ yếu sử dụng kỹ thuật này trong phát triển phần mềm cấp thấp; do đó, tôi luôn luôn sử dụng số nguyên không dấu. C thực hiện các thay đổi logic trên các số nguyên không dấu. Không chú ý đến bit dấu khi thực hiện dịch chuyển logic. Các bit được điền được chứa đầy số không. Tuy nhiên, C thực hiện thao tác dịch chuyển số học khi dịch chuyển một số nguyên có chữ ký. Các bit được điền vào được điền với bit dấu. Sự khác biệt này làm cho giá trị âm được làm tròn về vô cực thay vì bị cắt về 0, đây là một hành vi khác với phân chia số nguyên đã ký.
Một vài phút suy nghĩ dẫn đến một giải pháp đầu tiên. Giải pháp có điều kiện chuyển đổi giá trị âm thành giá trị dương trước khi dịch chuyển. Một giá trị được chuyển đổi có điều kiện trở lại dạng âm sau khi thao tác dịch chuyển được thực hiện.
int a = -5;
int n = 1;
int negative = q < 0;
a = negative ? -a : a;
a >>= n;
a = negative ? -a : a;
Vấn đề với giải pháp này là các câu lệnh gán có điều kiện thường được dịch sang ít nhất một lệnh nhảy và các lệnh nhảy có thể tốn kém trên các bộ xử lý không giải mã cả hai đường dẫn lệnh. Việc phải định lại một đường ống dẫn hai lần sẽ giúp cải thiện hiệu suất đạt được bằng cách chuyển qua chia.
Với những điều đã nói ở trên, tôi thức dậy vào thứ bảy với câu trả lời cho vấn đề chuyển nhượng có điều kiện. Vấn đề làm tròn mà chúng ta gặp phải khi thực hiện thao tác dịch chuyển số học chỉ xảy ra khi làm việc với biểu diễn bổ sung của hai. Nó không xảy ra với đại diện bổ sung của một người. Giải pháp cho vấn đề liên quan đến việc chuyển đổi giá trị bổ sung của hai thành giá trị bổ sung của một người trước khi thực hiện thao tác thay đổi. Sau đó, chúng tôi phải chuyển đổi giá trị bổ sung của một người trở lại giá trị bổ sung của hai. Đáng ngạc nhiên, chúng ta có thể thực hiện bộ hoạt động này mà không cần chuyển đổi có điều kiện các giá trị âm trước khi thực hiện thao tác thay đổi.
int a = -5;
int n = 1;
register int sign = (a >> INT_SIZE_MINUS_1) & 1
a = (a - sign) >> n + sign;
Giá trị âm bổ sung của hai được chuyển đổi thành giá trị âm bổ sung của một bằng cách trừ đi một giá trị âm. Mặt khác, giá trị âm bổ sung của một người được chuyển đổi thành giá trị âm bổ sung của hai bằng cách thêm một. Mã được liệt kê ở trên hoạt động vì bit dấu được sử dụng để chuyển đổi từ phần bù của hai sang phần bù của một và ngược lại . Chỉ các giá trị âm sẽ có các bit dấu của chúng được đặt; do đó, dấu biến sẽ bằng 0 khi a dương.
Với những điều đã nói ở trên, bạn có thể nghĩ về những vụ hack khôn ngoan khác như vụ lừa đảo ở trên đã biến nó thành túi của bạn không? Hack bit-khôn ngoan yêu thích của bạn là gì? Tôi luôn tìm kiếm các bản hack bit-bit định hướng hiệu suất mới.