Як "поки (i == i);" бути нескінченним циклом в одному потоковому додатку?


141

Щойно у мене виникло питання, на яке я не можу відповісти.

Припустимо, у вас є таке визначення циклу на Java:

while (i == i) ;

Який тип iта значення, iякщо цикл не є нескінченним циклом і програма використовує лише один потік ?


7
о, ради бога, чи мали би люди мати честь коментувати, чому вони зволікають? це позначено як загадку, в чому проблема ???
користувач54579

10
Я думаю, що деякі люди не можуть перестати виступати за щось.
FerranB

1
Ба, вибачте за те, що це спричинило: / Я дуже просто хотів відповіді, і я не міг її вирішити для себе.
Zizzencs

1
@nickolai, така природа SO - прискорення скорочення, на жаль, є реальністю, і ідея вимагати коментарів була обговорена та відхилена. Але схоже, що "громада" все-таки виступає за це питання.
paxdiablo

1
Один з прийомів подібного роду питань полягає в тому, що люди приймають тип певних імен змінних, тобто я є int, d - подвійний, s - рядок або короткий, ch - char, l - довгий, b для байт або булевий. Ви повинні запитати себе, який тип пропонується і що це може бути.
Пітер Лоурі

Відповіді:


125
double i = Double.NaN;

API для Double.equals () визначає відповідь: "Double.NaN == Double.NaN має значення false". Це детально розроблено у специфікації мови Java у розділі " Типи, формати та значення з плаваючою комою ":

NaNє неврегульованим, тому чисельні оператори порівняння <, <=, >і >= повернення , falseякщо один або обидва операнда NaN. Оператор рівності ==повертається, falseякщо будь-який операнд NaN, а оператор нерівності !=повертається, trueякщо будь-який операнд NaN. Зокрема, x!=xце trueтоді і тільки тоді , коли xISNaN , і (x<y) == !(x>=y)буде falseчи xабо yце NaN.


1
О, тож ви МОЖЕТЕ зробити "Не число"!
Філіп Екберг

12
математично твердий, чому одне нереальне число повинно дорівнювати іншому? 5/0! = Sqrt (-4)
Гордон Густафсон

2
@ CrazyJugglerDrummer: Можливо, але так само x == xзавжди має бути правдою. Чому щось не має собі рівних?
Барт ван Хекелом

1
Барт: адже дійсно, невідоме не завжди дорівнює невідомому. Іноді це корисно, тому в базах даних є NULL ...
Konerak

2
@inovaovao: ні, у БД null=nullнемає. NULL IS NULLє 1.
Конерак

29

Значення iтоді недійсне. "Не число".

Після деякого гуглінгу я дізнався, що ви можете мати NaN (не число) на Java! Отже, число плаваючої точки - це тип даних, а значення - NaN. Дивіться тут


12
Так, це все. Значення i - це Джон Скіт.
Ендрю Роллінгс

Я, як правило, ненавиджу людей, які не мають жодної причини ... Я був першим, хто сказав "Не число", але не думав, що Java може впоратися з цим, оскільки він не справляється з чим-небудь крутим.
Філіп Екберг



8

Я не впевнений, але я вважаю, що (i == i) не є атомною роботою в багатопотоковому процесі, тому якщо значення i буде змінено іншим потоком між натисканнями його значення, щоб укладатись на нитку, що виконує цикл, тоді ця умова може бути помилковим.


8

Оскільки інші сказали, що це NaN, мені цікаво офіційне впровадження (JDK 6) Double.isNaN, і ось:

/**
 * 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

Подумайте про Нан як еквівалент винятку, але використовуйте магічне значення в розрахунку. Оскільки обчислення не вдалося - наприклад, квадратний корінь від’ємника, розділити на нуль тощо - не має сенсу порівнювати їх із чим-небудь іншим. Зрештою, якщо ділення на нуль - це nan, це еквівалент квадратному кореню -2 або квадратному кореню -3?

Nan дозволяє розрахунок, який включає в себе крок, який повертає недійсну відповідь до завершення без введення додаткових винятків. Щоб перевірити відповідь, це значення просто перевірити на нежиттєздатність (це слово, якщо не я його мішу) через Float.isNan () o еквівалент.


3
Простіше було б подумати про це як exceptiolbut, якби я насправді знав, що таке exceptiolbut :-).
paxdiablo

2

Я додам

float i = Float.NaN;

так само, як

double i = Double.NaN;

Загальна хитрість у подібних питаннях, якщо ви вважаєте, що я є цілим. Іншими поширеними припущеннями можуть бути s - це String, x, y - це подвійний, ch - char, b - байт і т.д.

Подібне питання є; Це ніколи не циклічно, що таке "х"

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

Ще одне питання, яке мені дуже подобається, це; Ця петля - це нескінченний цикл, які можливі значення х. (: Я їх нараховую дванадцять :)

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

0

Я знаю, що це питання Java, але розгляд питання для інших мов інтригує.

У C такий простий тип, як "int", може виявити "закінчуватись до того, як Всесвіт стає холодною", якщо "i" було оголошено мінливим (тому компілятор буде змушений робити два читання "i" для кожної ітерації) і якщо "я" насправді був у пам'яті, де щось інше могло би вплинути на це. Тоді цикл закінчується, коли 'я' змінюється між двома читаннями однієї ітерації. ( Додано : можливе місце - в мікрокомп'ютері, де фактично розташований "i" за адресою порту вводу / виводу, можливо, підключений до датчика позиції. Це було б більш правдоподібно, якби "i" була змінною вказівника ( вказівник на мінливу пам'ять), а висловлювання було " while (*i == *i);".)

Як свідчать інші відповіді, в C ++ оператор '==' може бути наданий користувачем, якщо я є визначеним користувачем класом, тому все може бути можливим.

Замість NaN, мова, заснована на SQL, цикл не був би нескінченним, якби значення i було NULL; однак, будь-яке не-NULL значення зробить цикл нескінченним. Це швидше, як Java, де будь-яке число (на відміну від NaN) робить цикл нескінченним.

Я не бачу, щоб ця конструкція мала практичне використання, але це цікаве питання.


0

Я був здивований, що не бачив цього рішення:

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

У відповідь на коментар спробуйте виконати наступне:

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

x завжди повинен дорівнювати дузі (sin (x)) в теорії, але на практиці це не так.


3
Чому ні? Ви робите абсолютно однаковий розрахунок за точно однаковими даними, обидва результати будуть містити абсолютно однакову помилку.
Лорен Печтел

Я не можу точно пригадати, де я його прочитав, але залежно від вашої машини / реалізації, sin (x) на одному виклику функції має незначний шанс вирівняти sin (x) іншого виклику. Це пов'язано з точністю цифр з плаваючою точкою (щось особливе в функціях триггеру, що змушує їх не повертати одне і те ж значення двічі).
jkeys

Дивіться моє оновлення. Arcsine "скасовує" гріх x, тому вони повинні бути рівними, але вони не є.
jkeys

Це не те саме. Як сказала Лорен, ви виконуєте таку саму операцію x, яка повинна дати той самий результат із такою ж неточністю. Arcsin не може змінити результат гріха цифрами з плаваючою комою, тому що передане значення asin()не буде точно точним. Тому результат asin()буде неточним, роблячи x == asin(sin(x))помилковим. Крім того, arcsin не обов'язково «скасовує» операцію sin - функція sin може дати однаковий результат для декількох значень x, тому asin()лише повертає числа між -π / 2 та π / 2.
hbw

2
Іншими словами, arcsin не завжди може «скасувати» функцію sin, тому що arcsin не може знати, яким був початковий кут. Наприклад, гріх і π / 2, і 5π / 2 дають 1. Але що таке арцин (1)? Це, очевидно, не може повернути обох, правда? Тому результат дуги повинен бути обмежений діапазоном 2π радіанів, це означає, що він фактично не може скасувати результат функції sin, якщо початковий кут не знаходиться між 0 і 2π, або, у випадку С, -π / 2 і π / 2. (Дійсно, arcsin (sin (5π / 2)) = π / 2.) У будь-якому випадку, це було дійсно тривалим поясненням, але я сподіваюся, що це допоможе усунути будь-які помилки.
hbw

0

Не нескінченна петля, одна нитка :)

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 == iне є атомним. Доведено такою програмою:

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);
}

Оновлення Ось ще один приклад нескінченного циклу (нові нитки не створюються).

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 Що ви говорите про те, що немає можливості написати програму Java за допомогою одного потоку :), тому всі інші рішення використовують щонайменше дві нитки (точно такі ж, як і моя друга програма в розділі "Оновлення").
Андрій

Це не гальмує петлю. Будь-який код після while (i == i);звичаю ніколи не виконується.
aalku

Фіналізація використовує іншу нитку, але це добре зазначити. Це є причиною того, що в первинному запитанні було сказано, "і програма використовує лише одну нитку". Явно чітко заявляючи, що це очевидна відповідь, і вони хочуть, щоб ви подивились далі.
Білл К
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.