Vì vậy, tất cả chúng ta đều biết -1 > 2u == đúng
Các quy tắc so sánh có dấu/không dấu của C/C++ khá chuẩn và tôi có một tình huống muốn triển khai phép so sánh "đúng" một cách hiệu quả.
Câu hỏi của tôi là cách tiếp cận nào hiệu quả hơn khi xem xét càng nhiều kiến trúc mà mọi người quen thuộc càng tốt. Rõ ràng Intel và ARM có trọng số cao hơn.
Được cho:
số nguyên x;
số nguyên không dấu y;
nếu (x < y) {}
Có tốt hơn không khi quảng bá:
x < y => (int64)x < (int64)y
Hoặc tốt hơn nữa, hãy thực hiện 2 phép so sánh, cụ thể là:
x < y => (x < 0 || x < y)
Cái trước ngụ ý việc mở rộng bằng 0, mở rộng dấu và so sánh + nhánh, cái sau không yêu cầu thao tác mở rộng dấu nhưng yêu cầu 2 cmp + nhánh liên tiếp.
Theo quan niệm thông thường, việc phân nhánh tốn kém hơn việc mở rộng dấu hiệu và cả hai đều sẽ chạy theo đường ống, nhưng trong trường hợp đầu tiên, có một sự cố giữa việc mở rộng và phép so sánh đơn, trong khi ở trường hợp thứ hai, tôi có thể tưởng tượng một số kiến trúc có thể chạy theo đường ống 2 phép so sánh nhưng sau đó là 2 nhánh có điều kiện?
Có một trường hợp khác mà giá trị không dấu có kiểu nhỏ hơn kiểu có dấu, nghĩa là có thể thu được giá trị này bằng cách mở rộng giá trị bằng 0 một lần theo chiều dài của kiểu có dấu rồi thực hiện một phép so sánh duy nhất... Trong trường hợp này, nên sử dụng phiên bản extend+cmp hay phương pháp so sánh 2 vẫn được ưu tiên hơn?
Trí tuệ? CÁNH TAY? Còn gì nữa không? Tôi không chắc câu trả lời ở đây có đúng không, nhưng tôi muốn nghe ý kiến của mọi người. Hiệu suất cấp thấp rất khó dự đoán trong thời buổi ngày nay, đặc biệt là trên Intel và ARM.
biên tập:
Tôi cũng muốn nói thêm rằng có một giải pháp rõ ràng khi kích thước của kiểu bằng với chiều rộng int của kiến trúc; trong trường hợp này, giải pháp so sánh 2 rõ ràng được ưu tiên hơn, vì bản thân quá trình thăng cấp không thể thực hiện hiệu quả. Rõ ràng là của tôi số nguyên
Ví dụ này đáp ứng điều kiện này cho kiến trúc 32 bit và bạn có thể chuyển đổi thí nghiệm tư duy thành ngắn
để thực hiện các bài tập áp dụng cho nền tảng 32 bit.
CHỈNH SỬA 2:
Xin lỗi, tôi quên mất -1 > 2 bạn
TRONG bạn
! >_<
CHỈNH SỬA 3:
Tôi muốn sửa đổi trường hợp này để giả định rằng kết quả của phép so sánh là một nhánh thực tế và kết quả không được trả về dưới dạng giá trị bool. Đây là cấu trúc tôi thích; mặc dù nó nêu ra một điểm thú vị là khi kết quả là giá trị bool có nhánh, thì lại có một tập hợp các hoán vị khác.
số nguyên g;
void fun(int x, unsigned in y) { nếu((long long)x < (long long)y) g = 10; }
void gun(int x, unsigned in y) { nếu(x < 0 || x < y) g = 10; }
Điều này thường sẽ tạo ra nếu như
Nhánh mong đợi ngầm định khi ;)
Vâng, bạn đã mô tả tình huống một cách chính xác: C/C++ không thể thực hiện so sánh số nguyên có dấu/số nguyên không dấu đầy đủ bằng một phép so sánh duy nhất.
Tôi sẽ ngạc nhiên nếu việc nâng cấp lên int64 nhanh hơn việc thực hiện hai phép so sánh. Theo kinh nghiệm của tôi, trình biên dịch khá giỏi trong việc nhận ra rằng biểu thức con như vậy là thuần túy (không có tác dụng phụ), do đó nhánh thứ hai là không cần thiết. (Bạn cũng có thể chọn không tham gia việc đoản mạch một cách rõ ràng bằng cách sử dụng bitwise hoặc: (x < 0) | (x < 0)
. ) Ngược lại, kinh nghiệm của tôi là trình biên dịch có xu hướng không thực hiện nhiều tối ưu hóa trường hợp đặc biệt cho các số nguyên lớn hơn kích thước từ gốc, vì vậy (int64)x < (int64)y
Nhiều khả năng là một phép so sánh int đầy đủ thực sự đã được thực hiện.
Tóm lại, không có câu thần chú nào đảm bảo sẽ tạo ra mã máy tốt nhất có thể trên bất kỳ bộ xử lý nào, nhưng đối với các trình biên dịch phổ biến nhất trên hầu hết các bộ xử lý phổ biến, tôi đoán rằng biểu mẫu có hai phép so sánh sẽ không tốt hơn biểu mẫu được nâng cấp lên int64.
Chỉnh sửa: Một số cuộc thảo luận về Godbolt xác nhận rằng trên ARM32, GCC đưa quá nhiều công cụ vào các phương thức int64. VC cũng thực hiện điều tương tự trên x86. Tuy nhiên, đối với x64, phương pháp int64 thực sự ngắn hơn một lệnh (vì việc thăng hạng và so sánh 64 bit là rất đơn giản). Tuy nhiên, kỹ thuật pipeline có thể khiến hiệu suất thực tế kém hơn. https://godbolt.org/g/wyG4yC
Tôi là một lập trình viên xuất sắc, rất giỏi!