2013-07-13 45 views
12

Tôi đã viết một mô phỏng động vật ăn thịt nhỏ trong Java. Thậm chí nếu các quy định là khá phức tạp và kết thúc trong một hệ thống hỗn loạn các kỹ thuật sử dụng rất đơn giản:Java không xác định?

  • arithmetics và quyết định về các kiểu dữ liệu cơ bản
  • không thư viện bên ngoài
  • không hệ thống bên ngoài có
  • không đồng thời xảy ra
  • không sử dụng thời gian hiện tại hoặc ngày

Vì vậy, tôi nghĩ khi khởi tạo hệ thống với các thông số giống hệt nhau nên xuất kết quả giống hệt nhau, nhưng nó không và tôi tự hỏi tại sao.

Một số suy nghĩ về điều đó: Ứng dụng của tôi sử dụng Random s, nhưng đối với thử nghiệm đó, tôi khởi tạo tất cả với một giá trị nhất định, theo hiểu biết của tôi, chúng sẽ tạo cho mỗi lần chạy cùng một đầu ra theo cùng một thứ tự.

Tôi đang lặp lại thông qua Set giây và tôi biết rằng đơn đặt hàng Set được lặp lại không được xác định. Nhưng tôi không thấy bất kỳ lý do tại sao một Set được điền vào cùng một thứ tự với các giá trị giống nhau sẽ hoạt động khác nhau trong một số lần chạy. Phải không?

Tôi đang sử dụng rất nhiều float s. Các kiểu dữ liệu trong đó 1 + 1 = 1.9999999999725 luôn luôn là nghi ngờ đối với tôi, nhưng tôi thậm chí nếu hành vi của họ là lạ với tôi, nó phải luôn luôn là cùng một lạ. Phải không?

Bộ sưu tập rác không phải là xác định, nhưng miễn là tôi không dựa vào destructors tôi nên được an toàn.

Như đã nói ở trên, không có đồng thời và không có kiểu dữ liệu tùy thuộc vào thời gian thực tế sử dụng.

Tôi không thể sao chép hành vi đó trong một ví dụ đơn giản. Nhưng đi qua mã của tôi, tôi không thể thấy bất cứ điều gì có thể không đoán trước được. Vì vậy, có bất kỳ giả định của tôi ở trên sai? Bất kỳ ý tưởng những gì tôi có thể bị mất tích?

Dưới đây là một thử nghiệm để xác minh giả thuyết của tôi:

public static void main(String[] args) { 
    Random r = new Random(1); 
    Set<Float> s = new HashSet<Float>(); 
    for (int i = 0; i < 1000000; i++) { 
     s.add(r.nextFloat()); 
    } 

    float ret = 1; 
    int cnt = 0; 
    for (Float f : s) { 
     float multiply = 0.3f; 
     if (cnt++ % 2 == 0) { 
      multiply = 0.7f; 
     } 
     float f2 = (f * multiply); 
     ret += f2; 
    } 

    System.out.println(ret); 
} 

Nó là kết quả luôn trong 242.455,25 cho tôi.

+1

Chức năng thời gian? – Mysticial

+1

Khi bạn nói rằng bạn khởi tạo dữ liệu ngẫu nhiên của bạn, bạn có nghĩa là bạn sử dụng một hạt giống? – tjameson

+0

Điều này nghe có vẻ thú vị. Chúng tôi có thể xem mã của bạn không? – kol

Trả lời

20

Bạn có thể viết chương trình xác định trong Java. Bạn chỉ cần loại bỏ các nguồn không thể xác định được.

Thật khó để biết điều gì có thể gây ra không xác định mà không nhìn thấy mã thực tế của bạn và bằng chứng cụ thể về tính xác định đó.

Có bất kỳ số phương pháp thư viện nào có khả năng là nguồn hành vi không xác định ... tùy thuộc vào cách bạn sử dụng chúng.

Ví dụ: giá trị được trả về bởi Object.hashcode() (lần đầu tiên được gọi trên một cá thể) là không xác định. Và điều đó thấm qua bất kỳ thư viện nào sử dụng băm. Nó chắc chắn có thể ảnh hưởng đến thứ tự các thành phần của HashSet hoặc HashMap được trả lại khi bạn lặp lại chúng ... nếu lớp phần tử không ghi đè hashcode().

Máy tạo số ngẫu nhiên có thể hoặc không thể xác định được. Nếu chúng là giả ngẫu nhiên và chúng được khởi tạo với các hạt cố định, thì trình tự các số được tạo ra bởi mỗi hạt sẽ là xác định.

Số học dấu chấm động nên là xác định. Đối với bất kỳ bộ đầu vào (cố định) nào thành biểu thức số học, kết quả luôn luôn giống nhau. (Tôi không chắc rằng định mệnh của dấu chấm động số học được đảm bảo bởi JLS, nhưng nó sẽ là hùng mạnh kỳ lạ nếu nó xảy ra trong thực tế. Như trong ... bạn đang chạy trên phần cứng bị hỏng.)


THEO D 01I ... trên strictfp và không xác định.

Theo JLS 15.4:

"Trong vòng một biểu hiện đó không phải là FP-chặt chẽ, một số mất nhiều thời gian được cấp cho việc thực hiện sử dụng một loạt mũ mở rộng để đại diện cho kết quả trung gian; tác động ròng, khoảng nói rằng, một phép tính có thể tạo ra "câu trả lời đúng" trong các tình huống mà việc sử dụng độc quyền bộ giá trị nổi hoặc bộ giá trị kép có thể dẫn đến tràn hoặc tràn ".

này không chính xác nói bao nhiêu "mất nhiều thời gian" thực hiện có trong một biểu thức phi FP-nghiêm ngặt. Tuy nhiên, tôi đã nghĩ rằng khoảng cách đó sẽ không kéo dài để cho phép hành vi không xác định. Tôi đã nghĩ rằng một trình biên dịch JIT trên một nền tảng cụ thể sẽ luôn tạo ra mã nguồn gốc tương đương cho cùng một biểu thức, và mã đó sẽ là xác định. (Tôi không thể thấy bất kỳ lý do nào cho tính không xác định ... trừ khi bản thân phần cứng có điểm động không xác định.) Nguồn không thể xác định khác có thể là hành vi của mã biên dịch và giải mã JIT có thể khác nhau. Nhưng thành thật mà nói, tôi nghĩ rằng nó sẽ là "hạt" để cho phép điều đó xảy ra ... và tôi nghĩ chúng ta đã nghe về nó.

Vì vậy, trong khi đánh giá biểu hiện nghiêm ngặt không phải FP-có thể không xác định về lý thuyết, tôi nghĩ chúng ta nên giảm giá này ... trừ khi có bằng chứng rõ ràng rằng nó xảy ra trong thực tế.

(Lưu ý rằng tôi đang nói về thực phi định mệnh, không khác biệt nền tảng.)

+1

Xác định số học dấu chấm động không được đảm bảo mà không sử dụng 'strictfp' - nhưng điều đó chỉ nên ở trên các nền tảng. (+1) –

+0

Nếu không có 'strctfp', việc triển khai thực hiện miễn phí đôi khi sử dụng độ chính xác cao hơn và đôi khi không. –

+0

@PaulBellora - Yea. Biến đổi trên các nền tảng không giống với khái niệm không xác định. Nếu bạn đã thực sự không xác định, sau đó phần cứng fp của bạn là thiếu sót ... nếu không bị hỏng. –

10

Tôi lặp throu Sets, và tôi biết rằng thứ tự một Set được lặp không definied. Nhưng tôi không thấy bất kỳ lý do tại sao một Set được điền vào cùng một thứ tự với các giá trị giống nhau sẽ hoạt động differnet trong một số lần chạy. Phải không?

Có thể. Ví dụ, việc triển khai thực hiện miễn phí để sử dụng, vị trí của đối tượng trong bộ nhớ là khóa vào bảng băm bên dưới. Điều đó có thể khác nhau tùy thuộc vào thời điểm bộ sưu tập rác chạy.

+0

@MichaelBulla - Bạn đang sử dụng JVM nào? – tjameson

+0

@tjameson: Tôi không sử dụng bất kỳ JVM cụ thể nào. Câu hỏi này là về những gì * có thể xảy ra, không phải điều gì xảy ra. –

+0

Có vẻ như đó là một câu hỏi "không xảy ra", và tôi hy vọng rằng nếu OP cho chúng tôi biết JVM anh ta sử dụng cái gì, chúng tôi có thể tra cứu các ghi chú triển khai và xem điều này có khả năng gây ra bởi việc triển khai hay không. – tjameson

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