Nó chỉ ra rằng nó thực sự có thể làm điều này mà không có vòng lặp. Nó là nhanh nhất để tính toán trước (ít nhất) 8 bit phiên bản của vấn đề này. Tất nhiên, các bảng này sử dụng dung lượng bộ nhớ cache, nhưng vẫn có một tốc độ thực trong hầu hết các kịch bản máy tính hiện đại. Trong mã này, n = 0 lợi nhuận chút ít thiết lập, n = 1 là thứ hai-to-nhất vv
Giải pháp với __popcnt
Có một giải pháp sử dụng các __popcnt nội tại (bạn cần __popcnt để đạt được tốc độ cực nhanh hoặc bất kỳ lợi ích tuyệt vời nào trên một giải pháp vòng lặp đơn giản sẽ được khắc phục. May mắn thay hầu hết các bộ xử lý thời đại SSE4 + đều hỗ trợ nó).
// lookup table for sub-problem: 8-bit v
byte PRECOMP[256][8] = { .... } // PRECOMP[v][n] for v < 256 and n < 8
ulong nthSetBit(ulong v, ulong n) {
ulong p = __popcnt(v & 0xFFFF);
ulong shift = 0;
if (p <= n) {
v >>= 16;
shift += 16;
n -= p;
}
p = __popcnt(v & 0xFF);
if (p <= n) {
shift += 8;
v >>= 8;
n -= p;
}
if (n >= 8) return 0; // optional safety, in case n > # of set bits
return PRECOMP[v & 0xFF][n] << shift;
}
Điều này minh họa cách thức phân chia và cách tiếp cận chinh phục hoạt động.
chung Giải pháp
Ngoài ra còn có một giải pháp cho architectures- "chung" mà không __popcnt. Nó có thể được thực hiện bằng cách xử lý trong các khối 8 bit. Bạn cần một bảng tra cứu nhiều hơn cho bạn biết popcnt của một byte:
byte PRECOMP[256][8] = { .... } // PRECOMP[v][n] for v<256 and n < 8
byte POPCNT[256] = { ... } // POPCNT[v] is the number of set bits in v. (v < 256)
ulong nthSetBit(ulong v, ulong n) {
ulong p = POPCNT[v & 0xFF];
ulong shift = 0;
if (p <= n) {
n -= p;
v >>= 8;
shift += 8;
p = POPCNT[v & 0xFF];
if (p <= n) {
n -= p;
shift += 8;
v >>= 8;
p = POPCNT[v & 0xFF];
if (p <= n) {
n -= p;
shift += 8;
v >>= 8;
}
}
}
if (n >= 8) return 0; // optional safety, in case n > # of set bits
return PRECOMP[v & 0xFF][n] << shift;
}
Điều này có thể, tất nhiên, được thực hiện với một vòng lặp, nhưng dưới hình thức trải ra nhanh hơn và các hình thức khác thường của vòng lặp sẽ làm cho nó không chắc rằng trình biên dịch có thể tự động hủy bỏ nó cho bạn.
bạn có yêu cầu cho một phương pháp chung có thể được áp dụng để cung cấp cho bạn một cách để tính toán các bit thấp nhất thứ n cho bất kỳ n không đổi, hoặc làm bạn cần nó để làm việc cho bất kỳ n được đưa ra tại thời gian chạy? Dựa trên mô hình mặt nạ giảm của các loại hacks, tôi nghiêm túc nghi ngờ có một cách thanh lịch để làm thứ hai mà không có một cấu trúc lặp. –
Vâng, bạn cung cấp cả v và n khi chạy. Tôi cũng không thể nghĩ ra cách nào để làm điều đó mà không lặp lại. Thật khó để phân chia vấn đề, nhưng tôi không tin rằng không thể đánh bại một vòng lặp. – VoidStar