“ while (i = = i) ;”在单线程应用程序中如何成为非无限循环?

我只是有个无法回答的问题。

假设您在 Java 中有这个循环定义:

while (i == i) ;

如果循环不是无限循环和 程序只使用一个线程,那么 i的类型和值是什么?

8497 次浏览

然后 i的值无效。“非数字”。

经过一些谷歌,我发现你可以有 NaN (不是一个数字)在 Java!因此,浮点数是数据类型,值是 NaN。参见 给你

double i = Double.NaN;

Double.equals ()的 API 显示了答案: “ Double.NaN = = Double.NaN 的值为 false”。这一点在“ 浮点类型、格式和值”下的 Java 语言规范中有详细说明:

NaN是无序的,所以数字 比较运算符 <<=>>= 返回 false,如果其中一个或两个 操作数是 NaN 等式运算符 ==返回 false,如果 操作数为 NaN,而 如果不等式运算符 !=返回 true 两个操作数都是 NaN。 < strong > In 特别地,x!=xtrue当且仅当 如果 xNaN ,而 (x<y) == !(x>=y)会 如果 xyNaN,则 falsefalse

float i = Float.NaN;
while(i == i) ;
System.out.println("Not infinite!");
double i = Double.NaN;

NaN 不等于任何东西,包括它自己。

可以将 Nan 视为“例外”的等价物,但在计算中使用一个神奇的值。因为计算失败了——例如负数的平方根,除以零等等——把它们和其他东西进行比较是没有意义的。毕竟,如果除以零是一个 nan,它是等于 -2的平方根,还是等于 -3的平方根?

Nan 允许包含一个步骤的计算,该步骤返回一个无效的答案以完成计算,而不会引入额外的异常。要验证这个答案是否有价值,只需通过 Float.isNan () o 等价物对非 nandness 进行测试(如果没有包装,就是这个词)。

我不确定,但是我相信(i = = i)在多线程进程中不是原子操作,所以如果 i 值在其他线程推送它的值到执行循环的线程堆栈之间被其他线程更改,那么这个条件可能是假的。

我知道这是一个 Java 问题,但考虑到其他语言的问题是有趣的。

在 C 语言中,一个简单的类型,例如“ int”,如果“ i”被声明为一个易失性(因此编译器将被迫在每次迭代中对“ i”进行两次读取) ,并且“ i”实际上在内存中,其他的东西可能会影响它,那么它就会表现出“在宇宙变冷之前终止”的行为。然后循环将在单个迭代的两个读取之间发生“ i”更改时终止。(补充: 一个可能的位置-在微型计算机中,“ i”实际上位于一个 I/O 端口的地址,可能连接到一个位置传感器。如果‘ i’是一个指针变量(指向易失性内存的指针) ,而语句是‘ while (*i == *i);’,那么这种情况似乎更合理。)

正如其他答案所证明的那样,在 C + + 中,如果 i 是用户定义的类,那么用户可以提供’= =’运算符,因此任何事情都可能发生。

与 NaN 相似,在基于 SQL 的语言中,如果 i 的值为 NULL,则循环不会是无限的; 但是,任何非 NULL 值都会使循环成为无限的。这很像 Java,任何数字(与 NaN 相反)都会使循环无限。

我不认为这个结构有任何实际用途,但它是一个有趣的琐碎问题。

我要补充一句

float i = Float.NaN;

还有

double i = Double.NaN;

这类问题的一个常用技巧就是假设 i 是整型的。其他常见的假设可能是 s 是一个 String,x,y 是双精度的,ch 是一个 char,b 是一个字节,等等。 如果你看到一个像这样的问题,你可以打赌,“ i”不是它的预期类型。

一个类似的问题是: ,这个永远不会循环,“ x”是什么

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

另一个我很喜欢的问题是: 这个循环是一个无限循环,x 的可能值是什么(: 我数了四个,如@Clement 在下面指出的:)

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

我很惊讶没有看到这样的解决方案:

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

对于评论,请尝试运行以下命令:

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

理论上 x 应该总是等于反正弦(sin (x)) ,但实际上并非如此。

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

不是无限循环,是一个线程:)

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

由于其他人说它是 NaN,我对 Double.isNaN的官方实现(JDK 6)产生了好奇,看:

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