2015-11-04 24 views
8

Mã sau hoạt động như thế nào, đặc biệt khi bộ đếm đôi đạt đến giới hạn ((2-2^-52) · 2^1023)?Sử dụng Double.POSITIVE_INFINITY cho vòng lặp (Java)

for (double i = 0; i < Double.POSITIVE_INFINITY; i++){ 
    //do something 
} 

Mã này có hoạt động như mong đợi (lặp mãi mãi) hoặc không thành công tại một thời điểm nào đó và tại sao?

Cảm ơn.

+0

Tôi cho rằng không có gì đảm bảo rằng nó sẽ làm cho giá trị đó đạt được. Ai sẽ nói rằng 'i' sẽ không bị tràn trước khi bạn đạt tới giá trị đó do cách mà số học hai lần hoạt động? – Makoto

+0

Tại sao không thử? – Grodriguez

+0

@Makoto Đó là cơ bản những gì tôi yêu cầu. Trường hợp thú vị duy nhất ở đây là trường hợp cạnh. – Samir

Trả lời

5

Mã này sẽ không bao giờ thoát khỏi vòng lặp.

Lý do cho điều này là thêm 1 một số double đủ lớn không thay đổi giá trị của nó:

double a = 1.7976931348623155E308; 
double old = a; 
a++; 
System.out.println(a);  // prints 1.7976931348623155E308 
System.out.println(old); // prints 1.7976931348623155E308 
System.out.println(a==old); // prints "true" 

Demo.

Trong thực tế, khi giá trị của double được đủ gần đến vô cùng tích cực , bạn cần phải thêm một số trên 10 để tạo giá trị thay đổi lớn gấp đôi và trở thành POSITIVE_INFINITY.

Lý do cho điều này là cách double đại diện cho số lượng lớn. Nó sử dụng mantissa ngắn để biểu thị các chữ số có nghĩa nhất của giá trị và số mũ để chỉ ra vị trí đặt điểm thập phân. Trong trường hợp các số rất lớn, số mũ về cơ bản là một dấu hiệu cho biết có bao nhiêu số không cần phải được thêm vào sau khi biểu diễn nhị phân của mantissa.

Để làm cho giá trị thay đổi số double của bạn thông qua bổ sung, bạn cần phải thêm một số ít nhất cũng lớn như bit ít quan trọng nhất của phần định trị. Khi số mũ nhị phân vượt quá 48, số nhỏ nhất mà bạn cần thêm để kết quả khác nhau trở thành 2, có nghĩa là ++ sẽ không còn thay đổi giá trị.

+0

Liệu nó có hoàn toàn 0 hiệu lực? Không có thay đổi về bit hoặc bộ nhớ? Hay nó sẽ có tác dụng sau một số lượng lớn? Ngoài ra, "đủ lớn" có nghĩa là gì? – Samir

+2

@Samir Thêm một số lớn không có hiệu lực. Khi đơn vị dấu chấm động thấy rằng số mũ của hai số được thêm vào sẽ đặt các mantissas của chúng vào các phạm vi không giao nhau, đơn vị dừng lại và trả về giá trị của số lớn hơn. – dasblinkenlight

6

Tại một số điểm, i++ sẽ ngừng có hiệu lực, bởi vì đối với các giá trị rất lớn là i, giá trị double liên tiếp cách nhau rất xa.

Do đó, đó là vòng lặp vô hạn.

Để chứng minh có double giá trị mà i == i + 1 thử điều này:

for (double i = 1;; i *= 2){ 
    if (i == i + 1) { 
     System.out.println(i); 
     break; 
    } 
} 

It in

9.007199254740992E15 
+0

Thật thú vị, không biết điều đó. Liệu sự gia tăng ngừng có hiệu lực mãi mãi hay chỉ mất một thời gian dài để thấy sự thay đổi? Ngoài ra sẽ truy cập bao giờ tràn với vòng lặp này? – Samir

+2

@Samir nó không có tác dụng bao giờ hết. Nó không phải là "bí mật" bảo tồn sự gia tăng đâu đó; không có thay đổi nào cả khi 'i' đủ lớn. Khi 'i' nhận được giá trị đó, nó _stops thay đổi hoàn toàn_. –

+0

@Samir Giá trị điểm nổi không có độ phân giải vô hạn https://en.wikipedia.org/wiki/Unit_in_the_last_place là "bước" tối thiểu bạn cần phải thực hiện. Tại thời điểm này lớn hơn 1 – zapl

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