Làm thế nào để có thể trong khi (i == i); là một vòng lặp không vô hạn trong một ứng dụng luồng đơn?


141

Tôi chỉ có một câu hỏi mà tôi không thể trả lời.

Giả sử bạn có định nghĩa vòng lặp này trong Java:

while (i == i) ;

Loại ivà giá trị của inếu vòng lặp không phải là một vòng lặp vô hạn và chương trình chỉ sử dụng một luồng ?


7
oh vì chúa, mọi người có vinh dự bình luận về lý do tại sao họ downvote không? cái này được gắn thẻ như một câu đố, vấn đề là gì ???
dùng54579

10
Tôi nghĩ rằng một số người không thể ngừng downvote cho bất cứ điều gì.
FerranB

1
Bah, xin lỗi vì đã gây ra điều này: / Tôi thực sự chỉ muốn câu trả lời và tôi không thể tự giải quyết nó.
Zizzencs

1
@nickolai, đó là bản chất của SO - lái xe xuống bằng cách không may là một thực tế và ý tưởng yêu cầu bình luận đã được thảo luận và từ chối. Nhưng có vẻ như "cộng đồng" ủng hộ câu hỏi này.
paxdiablo

1
Một trong những thủ thuật của loại câu hỏi này là mọi người giả sử loại tên biến nhất định tức là tôi là số nguyên, d là số kép, s là chuỗi hoặc ngắn, ch là ký tự, l là số dài, b cho byte hoặc boolean. Bạn phải tự hỏi loại nào được đề xuất và nó có thể là gì.
Peter Lawrey

Câu trả lời:


125
double i = Double.NaN;

API cho Double.equals () đánh vần câu trả lời: "Double.NaN == Double.NaN có giá trị sai". Điều này được xây dựng trong Đặc tả ngôn ngữ Java trong " Các kiểu dấu phẩy động, định dạng và giá trị ":

NaNlà không có thứ tự, do đó số toán tử so sánh <, <=, >, và >= trở lại falsenếu một trong hai hoặc cả hai toán hạng là NaN. Toán tử đẳng thức ==trả về falsenếu một toán hạng là NaNvà toán tử bất đẳng thức !=trả về truenếu một toán hạng là NaN. Cụ thể, x!=xtruenếu và chỉ khi xNaN , và (x<y) == !(x>=y)sẽ là falsenếu xhoặc yNaN.


1
OH để bạn CÓ THỂ "Không phải là số"!
Filip Ekberg

12
Về mặt toán học của nó vững chắc, tại sao một số không thực bằng một số khác? 5/0! = Sqrt (-4)
Gordon Gustafson

2
@CrazyJugglerDrummer: Có thể, nhưng tương tự như vậy x == xphải luôn luôn đúng. Tại sao mọi thứ không nên bằng chính nó?
Bart van Heukelom

1
Bart: bởi vì thực sự, không biết không phải lúc nào cũng bằng không biết. Đôi khi nó rất hữu ích, đó là lý do tại sao cơ sở dữ liệu có NULL ...
Konerak

2
@inovaovao: không, trong DB, null=nulllà null. NULL IS NULLlà 1.
Konerak

29

Giá trị của isau đó là không hợp lệ. "Không phải là một con số".

Sau một vài lần googling, tôi phát hiện ra rằng bạn CÓ THỂ có NaN (Không phải là Số) trong Java! Vì vậy, số Float Pointing là Kiểu dữ liệu và Giá trị là NaN. Xem tại đây


12
Đúng, đó là nó. Giá trị của tôi là Jon Skeet.
Andrew Rollings

Tôi thường ghét những người downvote mà không có lý do ... Tôi là người đầu tiên nói "Không phải là số" nhưng không nghĩ java có thể xử lý điều đó, vì nó không xử lý bất cứ điều gì tuyệt vời khác.
Filip Ekberg



8

Tôi không chắc chắn, nhưng tôi tin rằng (i == i) không phải là hoạt động nguyên tử trong quy trình đa luồng, vì vậy nếu giá trị của tôi sẽ bị thay đổi bởi luồng khác giữa các lần đẩy giá trị của nó để xếp chồng lên luồng thực hiện vòng lặp, thì điều kiện đó có thể là sai


8

Vì những người khác nói rằng đó là NaN, tôi đã tò mò về việc triển khai chính thức (JDK 6) Double.isNaNvà kìa:

/**
 * Returns <code>true</code> if the specified number is a
 * Not-a-Number (NaN) value, <code>false</code> otherwise.
 *
 * @param   v   the value to be tested.
 * @return  <code>true</code> if the value of the argument is NaN;
 *          <code>false</code> otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}

2

Hãy nghĩ về Nan tương đương với ngoại lệ nhưng sử dụng giá trị ma thuật trong phép tính. Bởi vì một phép tính thất bại - ví dụ căn bậc hai của âm, chia cho số 0, v.v. - không có ý nghĩa gì khi so sánh chúng với bất kỳ thứ gì khác. Xét cho cùng, nếu chia cho 0 là một nan thì nó có tương đương với căn bậc hai của -2 hoặc căn bậc hai của -3 không?

Nan cho phép một phép tính bao gồm một bước trả về một câu trả lời không hợp lệ để hoàn thành mà không đưa ra các ngoại lệ bổ sung. Để xác minh câu trả lời là giá trị, chỉ cần kiểm tra mức độ không nghiêm trọng (đó là từ nếu không tôi đóng gói) thông qua Float.isNan () o tương đương.


3
Sẽ dễ dàng hơn khi nghĩ về nó như ngoại trừ nếu tôi thực sự biết ngoại lệ là gì :-).
paxdiablo

2

Tôi sẽ thêm

float i = Float.NaN;

cũng như

double i = Double.NaN;

Một mẹo phổ biến trong các loại câu hỏi này trong giả định bạn đưa ra rằng tôi là một int. Các giả định phổ biến khác có thể là s là String, x, y là double, ch là char, b là byte, v.v ... Nếu bạn thấy một câu hỏi như thế này, bạn có thể đặt cược rằng 'i' không phải là loại mong đợi của nó.

Một câu hỏi tương tự là; Điều này không bao giờ lặp, 'x' là gì

while(x == x && x != x + 0) { }

Một câu hỏi khác tôi khá thích là; Vòng lặp này là một vòng lặp vô hạn, các giá trị có thể có của x là gì. (: Tôi đếm mười hai người trong số họ :)

while(x != 0 && x == -x) { }

0

Tôi biết đây là một câu hỏi Java, nhưng xem xét câu hỏi cho các ngôn ngữ khác là hấp dẫn.

Trong C, một loại đơn giản như 'int' có thể biểu hiện 'chấm dứt trước khi vũ trụ trở nên lạnh' nếu 'i' được tuyên bố là không ổn định (vì vậy trình biên dịch sẽ buộc phải thực hiện hai lần đọc 'i' cho mỗi lần lặp) và nếu 'tôi' thực sự nằm trong bộ nhớ nơi mà thứ khác có thể ảnh hưởng đến nó. Sau đó, vòng lặp sẽ chấm dứt khi 'i' thay đổi giữa hai lần đọc của một lần lặp. ( Đã thêm : một vị trí có thể - trong một máy vi tính nơi 'i' thực sự được đặt tại địa chỉ của cổng I / O, có lẽ được kết nối với cảm biến vị trí. Sẽ hợp lý hơn nếu 'i' là biến con trỏ ( một con trỏ tới bộ nhớ dễ bay hơi) và câu lệnh là ' while (*i == *i);'.)

Bằng chứng là các câu trả lời khác, trong C ++, toán tử '==' có thể được cung cấp bởi người dùng nếu tôi thuộc lớp do người dùng định nghĩa, vì vậy mọi thứ đều có thể.

Thay vì NaN, trong ngôn ngữ dựa trên SQL, vòng lặp sẽ không vô hạn nếu giá trị của i là NULL; tuy nhiên, bất kỳ giá trị không phải NULL nào cũng sẽ làm cho vòng lặp trở nên vô hạn. Điều này khá giống với Java, trong đó bất kỳ số nào (trái ngược với NaN) làm cho vòng lặp là vô hạn.

Tôi không thấy các cấu trúc có bất kỳ sử dụng thực tế, nhưng đó là một câu hỏi đố thú vị.


0

Tôi đã rất ngạc nhiên khi không thấy giải pháp này:

while (sin(x) == sin(x)) //probably won't eval to true

Để trả lời một bình luận, hãy thử chạy nó:

double x = 10.5f;
assert (x == asin(sin(x)));

x luôn luôn phải bằng arcsine (sin (x)) trong lý thuyết, nhưng trong thực tế thì không.


3
Tại sao không? Bạn đang thực hiện chính xác cùng một phép tính trên cùng một dữ liệu, cả hai kết quả sẽ chứa chính xác cùng một lỗi.
Loren Pechtel

Tôi không thể nhớ chính xác nơi tôi đã đọc nó, nhưng tùy thuộc vào máy / cách triển khai của bạn, sin (x) trên một lệnh gọi hàm có cơ hội rất nhỏ bằng với sin (x) của một cuộc gọi khác. Nó phải làm với độ chính xác của các chữ số dấu phẩy động (một điều đặc biệt về các hàm lượng giác khiến chúng không trả về cùng một giá trị hai lần).
lừa

Xem cập nhật của tôi. Arcsine "hoàn tác" tội lỗi của x, vì vậy chúng nên bằng nhau, nhưng chúng không như vậy.
lừa

Đó không phải là điều tương tự. Giống như Loren đã nói, bạn đang thực hiện chính xác thao tác trên x, điều này sẽ mang lại kết quả chính xác tương tự với độ chính xác tương tự. Arcsin không thể đảo ngược kết quả của một tội lỗi với các số dấu phẩy động bởi vì giá trị được chuyển đến asin()sẽ không chính xác. Do đó, kết quả asin()sẽ không chính xác, làm x == asin(sin(x))sai. Ngoài ra, arcsin không nhất thiết phải "hoàn tác" một hoạt động tội lỗi. Hàm sin có thể cho cùng một kết quả cho nhiều giá trị của x, đó là lý do tại sao asin()chỉ trả về các số giữa -π / 2 và π / 2.
hbw

2
Nói cách khác, arcsin không thể luôn "hoàn tác" chức năng tội lỗi vì arcsin không thể biết góc ban đầu là gì. Ví dụ: tội lỗi của cả π / 2 và 5π / 2 cho 1. Nhưng arcsin (1) là gì? Nó rõ ràng không thể trả lại cho cả hai, phải không? Do đó, kết quả của arcsin phải được giới hạn trong phạm vi 2π radian, nghĩa là nó thực sự không thể hoàn tác kết quả của hàm sin trừ khi góc ban đầu nằm trong khoảng từ 0 đến 2π, hoặc trong trường hợp của C, -π / 2 và / 2. (Thật vậy, arcsin (sin (5π / 2)) = π / 2.) Dù sao, đó là một lời giải thích thực sự dài, nhưng tôi hy vọng điều đó sẽ giúp làm sáng tỏ mọi hiểu lầm.
hbw

0

Không phải vòng lặp vô hạn, một chủ đề :)

import static B.*;
public class A {
    public static void main(String[] args) {
        System.out.println("Still Running");
        while (i == i) ;
    }
}


public class B {

    public static int i;
    static {
        System.exit(0);
    }
}

-1

i == ikhông phải là nguyên tử. Chứng minh bởi chương trình như vậy:

static volatile boolean i = true;
public static void main(String[] args) throws InterruptedException
{
    new Thread() {
        @Override
        public void run() {
            while (true) {
                i = !i;
            }
        }
    }.start();

    while (i == i) ;
    System.out.println("Not atomic! i: " + i);
}

Cập nhật Dưới đây là một ví dụ nữa về vòng lặp không vô hạn (không có chủ đề mới nào được tạo).

public class NoNewThreads {
    public static void main(String[] args) {
        new NoNewThreads();
        System.gc();
        int i = 500;
        System.out.println("Still Running");
        while (i == i) ;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        Thread.sleep(1000);
        System.exit(0);
    }
}

@Charles Goodwin Bạn nói gì với thực tế là không có khả năng viết chương trình Java bằng một luồng :), vì vậy tất cả các giải pháp khác đều sử dụng ít nhất hai luồng (giống hệt như chương trình thứ hai của tôi trong phần 'Cập nhật').
Andrey

Đó không phải là phanh vòng. Bất kỳ mã sau khi while (i == i);không bao giờ thực hiện.
aalku

Hoàn thiện sử dụng một chủ đề khác, nhưng đó là một điều tốt để chỉ ra. Đó là lý do câu hỏi ban đầu nói "và chương trình chỉ sử dụng một luồng" .. loại nói rõ ràng rằng đây là câu trả lời rõ ràng và họ muốn bạn nhìn xa hơn.
Bill K
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.