2012-06-13 86 views
14
int i = 0, j = 0; 
double nan1 = (double)0/0; 
double nan2 = (double)0/0; 
double nan3 = (double)i/j; 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2)); 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0)); 
System.out.println(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2)); 

đầu ra:Lẫn lộn trên NaN trong Java

true 
true 
false 

Xin hãy giúp tôi làm thế nào đầu ra đến true cho hai đầu tiên và false cho người cuối cùng. Vui lòng cho tôi biết công việc thực tế của phương pháp Double.doubleToRawLongBits() là gì.

+0

Có hai 'NaN' khác nhau được tạo ra. Một là '0x7ff8000000000000' và cái kia là' 0xfff8000000000000'. Phần cứng dường như cung cấp '0xfff8000000000000' cho' 0/0'. Tuy nhiên, tuyên truyền liên tục của trình biên dịch đang sử dụng '0x7ff8000000000000' thay thế. Trừ khi tôi bỏ qua một cái gì đó, điều này trông giống như một lỗi cho tôi. – Mysticial

+0

Nếu bạn bật 'strictfp' cho phương thức thì sao? – Joey

+5

Ngoài ra: »Trong IEEE 754 định dạng lưu trữ điểm nổi phù hợp tiêu chuẩn, NaN được xác định bằng các mẫu bit cụ thể, được xác định trước duy nhất cho các NaN. Bit đăng nhập không quan trọng. «([Wikipedia] (http://en.wikipedia.org/wiki/NaN#Encoding)) – Joey

Trả lời

3

Hãy cố gắng chạy đoạn mã sau để xem các giá trị:

public class Test 
{ 
    public static void main(String[] args){ 
     int i = 0, j = 0; 
     double nan1 = (double)0/0; 
     double nan2 = (double)0/0; 
     double nan3 = (double)i/j; 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2))); 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits((double)0/0) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0))); 
     System.out.println(Double.doubleToRawLongBits(nan3) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2))); 
    } 
} 

Trên Mac của tôi, nó tạo ra sau đầu ra:

9221120237041090560 == 9221120237041090560 is true 
9221120237041090560 == 9221120237041090560 is true 
-2251799813685248 == 9221120237041090560 is false 

cạm bẫy này được diễn tả trong Javadoc cho doubleToRawLongBits method:

Nếu đối số là NaN, kết quả là số nguyên dài thể hiện giá trị NaN thực tế. Không giống như phương thức doubleToLongBits, doubleToRawLongBits không thu gọn tất cả các mẫu bit mã hóa một NaN thành một giá trị NaN "chuẩn" duy nhất.

+2

Điều này có trả lời câu hỏi không? – Mysticial

+0

Mã giống như trong câu hỏi quá thừa; nhưng sau liên kết tới các tài liệu * thì * trả lời câu hỏi, mặc dù với một hướng dẫn. Tôi đã chỉnh sửa phần liên quan dưới dạng trích dẫn. Nhưng tôi muốn nói rằng tất cả mọi thứ ở trên đó chỉ là rác mà không có gì để làm với một câu trả lời. – Joey

+0

Tôi không nghĩ rằng điều này giải quyết được sự nhầm lẫn của tôi về vấn đề này. –

1

Tôi nghĩ Java theo IEEE 754. Trong trường hợp này, NaN có nhiều hơn một biểu diễn bit có thể. Hai biểu diễn trong trường hợp của bạn khác nhau trong bit "sign". Giá trị của bit dấu có vẻ không được xác định bởi tiêu chuẩn và thường bị bỏ qua. Vì vậy, cả hai giá trị đều chính xác. Xem http://en.wikipedia.org/wiki/NaN

0

Lý do là vì khi bạn chia biến đôi 0 thành 0 nó trả về NaN, vì vậy phương thức không có một biểu diễn chuẩn trong nhị phân, vì vậy nó có thể trả về nhị phân NaN là 7F F8 00 00 00 00 00 00 hoặc FF F8 00 00 00 00 00 00

Mặc dù về mặt kỹ thuật chúng đại diện cho cùng một thứ, đó là NaN, khác biệt của nó trong biểu diễn nhị phân.

2

Chuẩn IEEE 754 cho phép các mẫu bit khác nhau cho NaN. Đối với mục đích tính toán và so sánh, tất cả chúng đều hoạt động giống nhau (ví dụ: NaN so sánh không bằng với chính nó, không được đặt hàng và mọi tính toán liên quan đến NaN là chính bản thân số NaN). Với doubleToRawLongBits bạn nhận được mẫu bit chính xác được sử dụng. Điều này cũng được nêu chi tiết trong JLS:

Đối với hầu hết các phần, các nền tảng Java đối xử với các giá trị NaN của một loại nhất định như dù sụp đổ thành một giá trị kinh điển duy nhất (và do đó đặc tả này nor- Mally đề cập đến một tùy ý NaN như một giá trị kinh điển). Tuy nhiên, phiên bản 1.3 nền tảng Java đã giới thiệu các phương pháp cho phép lập trình viên phân biệt giữa các giá trị NaN: các phương pháp Float.floatToRawIntBitsDouble.double- ToRawLongBits. Người đọc quan tâm được tham chiếu đến thông số kỹ thuật cho các lớp học FloatDouble để biết thêm thông tin.

Trong trường hợp của bạn bit dấu là khác nhau, trong trường hợp này tôi có thể hướng dẫn bạn đến Wikipedia, tóm tắt này ngắn gọn:

Trong IEEE 754 định dạng lưu trữ điểm nổi tiêu chuẩn phù hợp, Nans được xác định theo các mẫu bit cụ thể, được xác định trước duy nhất cho NaN. Bit dấu không quan trọng.

Cả hai giá trị của bạn là NaN, chúng chỉ sử dụng các bit khác nhau để biểu thị điều đó. Một cái gì đó được cho phép bởi IEEE 754 và trong trường hợp này có thể xuất phát từ trình biên dịch thay thế Double.NaN cho một phép tính không đổi kết quả trong NaN trong khi phần cứng thực tế cho kết quả khác, như bị nghi ngờ bởi Mysticial trong một nhận xét cho câu hỏi đã có.

+0

Joey là trình biên dịch chọn các mẫu bit khác nhau ngẫu nhiên cho các giá trị NaN. Nếu không, thì tại sao cùng một mô hình cho nan1 và nan2 nhưng mô hình khác nhau cho nan3. –