2009-11-29 33 views
7

Tôi cần tìm thứ tự cao nhất 1 trong một số thời gian, số nguyên và quần short trong Java. Ví dụ, nếu tôi có một char trông giống như 00110101, tôi cần một phương thức sẽ trả về 2 (chỉ số thứ tự cao nhất 1).Tìm thứ tự cao nhất 1 trong Java nguyên thủy

Bây giờ, tôi biết rằng bạn có thể làm điều này bằng cách sử dụng vòng lặp for như:

for(int i=0; i<8; i++) 
    if((x & 1<<i) != 0) return i; 
return -1; 

nhưng đây là cách chậm hơn so với những gì tôi muốn làm. Tôi biết các CPU hiện đại có hướng dẫn làm điều này trên chip, vì vậy tôi muốn biết làm thế nào tôi có thể thực hiện cuộc gọi đến đó thay vì có một vòng lặp rõ ràng.

CHỈNH SỬA: Điểm thưởng nếu bạn chỉ có thể trả về các chỉ mục của tất cả các số nguyên trong số nguyên thủy.

Cảm ơn.

+0

Bạn có đang chạy trên một máy tính lớn không? – int3

+0

Tôi đã được ấn tượng rằng Java xử lý endianess theo cách riêng của mình trong JVM, nhưng giả sử nó không, tôi sẽ sử dụng một C2D Intel, rất ít endian. – twolfe18

+0

Chạy mã của bạn, tôi nhận được 0, không phải 2. – Buhb

Trả lời

11

Integer.numberOfLeadingZeros(i) + 1

Đó phương pháp sử dụng một cách tiếp cận thoải mái chia-và-chinh phục, sao chép vào đây để đánh giá của bạn:

public static int numberOfLeadingZeros(int i) { 
    // HD, Figure 5-6 
    if (i == 0) 
     return 32; 
    int n = 1; 
    if (i >>> 16 == 0) { n += 16; i <<= 16; } 
    if (i >>> 24 == 0) { n += 8; i <<= 8; } 
    if (i >>> 28 == 0) { n += 4; i <<= 4; } 
    if (i >>> 30 == 0) { n += 2; i <<= 2; } 
    n -= i >>> 31; 
    return n; 
} 
+0

Thuật toán là thanh lịch, nhưng chuyển dịch là AFAIK chậm khủng khiếp. –

+1

Tốt hơn để thay đổi 8 lần (trường hợp xấu nhất), hơn 32, như khái quát vòng lặp từ câu hỏi sẽ. (Và đó là giả định JIT-Compiler unrolls vòng lặp, nếu không chi phí chi nhánh sẽ thống trị. – meriton

+4

Có một tài liệu tham khảo cho chuyển là "khủng khiếp chậm" trong Java? Tôi chưa bao giờ nghe nói rằng .. – PSpeed

0

Tôi không biết về việc nhấn lệnh CPU, nhưng tôi biết rằng điều này sẽ nhanh hơn rất nhiều nếu bạn bỏ vòng lặp và sử dụng mặt nạ bit rõ ràng.

Ngoài ra, một char không phải là 8 bit ... Tôi nghĩ bạn có thể có nghĩa là một byte.

+0

Tôi đã suy nghĩ của C phong cách char (họ đang 8 bit phải không? ...). Các ký tự của Java có phải là 2 byte cho hỗ trợ unicode không? – twolfe18

+0

Vâng, đúng vậy. –

3

Trang "Bit Twiddling Hacks" chứa nhiều hacks bit. Một cách là tìm số index of the highest order bit.

+0

Tôi đã từng sử dụng các thuật toán này trong mã Java của mình, nhưng hầu hết trong số chúng đã được thêm vào API nền tảng trong vài năm qua. – finnw

+0

Tuy nhiên phương pháp trình tự de Bruijn vẫn nhanh hơn phương pháp phân chia và conquer được sử dụng trong 'numberOfLeadingZeros' và' numberOfTrailingZeros' được tích hợp sẵn. – finnw

0

Theo như tôi có thể nói, Pentium và bạn bè không có hướng dẫn sẵn sàng cho việc này. Vì vậy, điều cần làm là sử dụng một thuật toán phong nha.

Chìa khóa để nhận câu trả lời của bạn nhanh chóng là sử dụng tìm kiếm nhị phân. Bạn đang xem một số long với 64 bit? 6 so sánh sẽ cung cấp cho bạn bit cao nhất của bạn, mỗi lần.

Mã hoạt động với một cây xấu xí lớn gồm 64 câu lệnh, nhưng chỉ một phần nhỏ sẽ được thực thi, vì vậy thời gian chạy là tốt.

Nếu bạn cần mã mẫu, tôi có thể làm điều đó. Nhưng tôi không muốn.

+0

Nó không cần phải được thể hiện bằng cách sử dụng một cây, xem câu trả lời của tôi. – meriton

+0

Như tôi đã nhận xét, tôi thích sự thanh lịch của mã nhưng tôi nghi ngờ hiệu suất của nó là chấp nhận được. –

1

Tôi không có ý tưởng nếu điều này là nhanh hơn. Nhưng nó không có vòng lặp.

if(i==0) return -1; 

highest=0; 
if (i & 0xffff0000) 
{ 
    highest+=16; 
    i>>=16; 
} 
if (i & 0xff00) 
{ 
    highest+=8; 
    i>>=8; 
} 
if (i & 0xf0) 
{ 
    highest+=4; 
    i>>=4; 
} 
if (i & 0xC) 
{ 
    highest+=2; 
    i>>=2; 
} 
if (i & 0x2) 
{ 
    highest+=1; 
} 

return highest; 
0

Java được biên dịch thành bytecode độc ​​lập nền tảng, bạn không thể mong đợi hỗ trợ cho hướng dẫn CPU. Nếu không, mã của bạn hoặc Integer.highestOneBit() phải nhanh như nó được.

+0

tốt, tôi đồng ý về nguyên tắc, nhưng tôi nghĩ rằng java không làm một số điều trong nền tảng phụ thuộc cách (cho hiệu quả), nhưng họ rơi trở lại trên một java thực hiện nếu nền tảng không hợp tác.Tôi đã hy vọng đây là một trong số họ ... – twolfe18

+1

Tất nhiên các JVM là nền tảng cụ thể, nhưng đối với trường hợp của bạn trình biên dịch JIT wou ld phải phát hiện ý định thực sự của bạn từ bytecode, điều này có thể khó khăn. Nhưng nếu tốc độ là bản chất, bạn có thể cân nhắc sử dụng trình kết hợp độc lập với nền tảng, tức là thư viện C và JNI. – FelixM

0

Có giống như sau này không?

System.out.println("00110101".indexOf("1")); 
+0

:) ... tôi ước, nhưng không có – twolfe18

+0

haha ​​- đó là khá buồn cười. Nhắc tôi về một lập trình viên mà tôi đã có một nhân viên đã chuyển đổi một số thành một chuỗi để anh ta có thể làm tròn nó. Oy. –

Các vấn đề liên quan