2015-11-16 19 views
6

Trước khi tìm phương thức Long.numberOfLeadingZeros(long i), tôi đã đúc thời gian để tăng gấp đôi và sử dụng Math.getExponent(double d). Ý tưởng là để tìm đại diện đôi của dài, sử dụng số mũ để có được bit thiết lập cao nhất, và trừ nó từ 64 để có được số lượng các số không đứng đầu.Java - tìm số 0 đứng đầu trong một thời gian dài bằng cách chuyển đổi thành hai lần

này chủ yếu là làm việc, nhưng thỉnh thoảng tắt bằng 1. Sau đây cho vòng lặp được sử dụng để làm nổi bật vấn đề:

for (int i = 0; i < 64; i++) { 
    double max = Long.MAX_VALUE >>> i; 
    double min = Long.MIN_VALUE >>> i; 
    double neg = -1L >>> i; 
    System.out.format("Max: %-5d Min: %-5d -1: %-5d%n", Math.getExponent(dmax), 
           Math.getExponent(dmin), Math.getExponent(dneg)); 
} 

với phần đáng kể sản lượng:

... 
Max: 55 Min: 55 -1: 56 
Max: 54 Min: 54 -1: 55 
Max: 52 Min: 53 -1: 54 
Max: 51 Min: 52 -1: 52 
Max: 50 Min: 51 -1: 51 
... 

Các chờ đợi với tất cả các bit được đặt bằng 1 trên 2^52. As this post explains, mất chính xác xảy ra do lưu trữ 53 bit quan trọng trong phần mềm 52 bit. Tuy nhiên, tôi đang đấu tranh để hiểu tại sao số mũ bị ảnh hưởng.

Trong khi tôi không còn sử dụng phương pháp này nữa, tôi vẫn tò mò: tại sao và trong hoàn cảnh nào thì phương pháp tìm kiếm số 0 đứng đầu trong một thất bại dài?

Trả lời

3

Giới hạn độ chính xác trên double buộc đại diện nhị phân làm tròn thành công suất gần nhất là 2, tăng số mũ trong biểu diễn dấu phẩy động của giá trị double. Điều này xảy ra bởi vì một phần tử của double, bao gồm bit 1 ngụ ý, là 53 bit, nhưng một bit là long có 64 bit.

Section 5.1.2 of the JLS bao gồm những gì có thể xảy ra trong này chuyển đổi nguyên thủy mở rộng:

Chuyển đổi nguyên thủy ngày càng lớn từ int nổi, hoặc từ lâu nổi, hoặc từ lâu để tăng gấp đôi, có thể dẫn đến việc mất độ chính xác - đó là, kết quả có thể mất một số bit quan trọng nhất của giá trị. Trong trường hợp này, giá trị dấu chấm động kết quả sẽ là phiên bản được làm tròn chính xác của giá trị số nguyên, sử dụng chế độ vòng tròn gần nhất của IEEE 754 (§4.2.4).

(tôi nhấn mạnh)

Ở đây, tôi sử dụng Double.doubleToLongBits để bảo tồn các bit của một double trong một long, và Long.toHexString để in ra các giá trị hex của bản gốc double s.

System.out.format("Max(%s): %-5d Min(%s): %-5d -1(%s): %-5d%n", 
       Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmax), 
       Long.toHexString(Double.doubleToLongBits(dmax)), Math.getExponent(dmin), 
       Long.toHexString(Double.doubleToLongBits(dneg)), Math.getExponent(dneg)); 

Output:

Max(43e0000000000000): 63 Min(43e0000000000000): 63 -1(bff0000000000000): 0  
Max(43d0000000000000): 62 Min(43d0000000000000): 62 -1(43e0000000000000): 63 
Max(43c0000000000000): 61 Min(43c0000000000000): 61 -1(43d0000000000000): 62 
Max(43b0000000000000): 60 Min(43b0000000000000): 60 -1(43c0000000000000): 61 
Max(43a0000000000000): 59 Min(43a0000000000000): 59 -1(43b0000000000000): 60 
Max(4390000000000000): 58 Min(4390000000000000): 58 -1(43a0000000000000): 59 
Max(4380000000000000): 57 Min(4380000000000000): 57 -1(4390000000000000): 58 
Max(4370000000000000): 56 Min(4370000000000000): 56 -1(4380000000000000): 57 
Max(4360000000000000): 55 Min(4360000000000000): 55 -1(4370000000000000): 56 
Max(4350000000000000): 54 Min(4350000000000000): 54 -1(4360000000000000): 55 
Max(433fffffffffffff): 52 Min(433fffffffffffff): 53 -1(4350000000000000): 54 
Max(432ffffffffffffe): 51 Min(432ffffffffffffe): 52 -1(433fffffffffffff): 52 

Các long giá trị ban đầu với hơn 53 1 bit được làm tròn lên khi chuyển đổi sang một double, mất độ chính xác. Trường số mũ bao gồm các bit 2 đến 12, hiển thị trong 3 số hex đầu tiên được in ở trên.

Khi giá trị được dịch chuyển dưới mức 53 1 bit, độ chính xác của double hiện đủ để giữ giá trị mà không làm tròn (vòng tròn không còn cần thiết) và bit của mantissa được hiển thị dưới dạng chữ số thập phân 'f'.Có sự gián đoạn trong trường số mũ, chuyển từ 435 sang 433, giải thích lý do tại sao có gián đoạn do kết quả của Math.getExponent, từ 54 đến 52.

+0

Điều này có ý nghĩa hoàn hảo. Sau khi đọc bài viết của bạn, tôi buộc các giá trị lớn hơn 2^53 - 1 để giảm 11 bit quan trọng nhất của chúng bằng: 'value & = 0xFFFFFFFFFFFFF700L;' trước khi chuyển đổi thành một đôi, làm cho làm tròn không cần thiết. Tôi cũng quên phần định nghĩa có chút hàm ý. Cảm ơn các câu trả lời chi tiết! –

1

Một số có tất cả, khi được làm tròn đến ít vị trí hơn sẽ được làm tròn lên và do đó sẽ dài hơn một chút. Ví dụ: (giả sử một đôi chỉ có 5 bit trong mantissa)

111111 becomes 1000000 

khi làm tròn.

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