谜题33:循环者遇到了狼人

请提供一个对i的声明,将下面的循环转变为一个无限循环。这个循环不需要使用任何5.0版的特性:


while (i != 0 && i == -i) {

}

这仍然是一个循环。在布尔表达式(i != 0 && i == -i)中,一元减号操作符作用于i,这意味着它的类型必须是数字型的:一元减号操作符作用于一个非数字型操作数是非法的。因此,我们要寻找一个非0的数字型数值,它等于它自己的负值。NaN不能满足这个属性,因为它不等于任何数值,因此,i必须表示一个实际的数字。肯定没有任何数字满足这样的属性吗?

嗯,没有任何实数具有这种属性,但是没有任何一种Java数值类型能够对实数进行完美建模。浮点数值是用一个符号位、一个被通俗地称为尾数(mantissa)的有效数字以及一个指数来表示的。除了0之外,没有任何浮点数等于其符号位反转之后的值,因此i的类型必然是整数型的。

有符号的整数类型使用的是2的补码算术运算:为了对一个数值取其负值,你要反转其每一位,然后加1,从而得到结果[JLS 15.15.4]。2的补码算术运算的一个很大的优势是,0具有唯一的表示形式。如果你要对int数值0取负值,你将得到0xffffffff+1,它仍然是0。

但是,这也有一个相应的不利之处,总共存在偶数个int数值——准确地说有232个——其中一个用来表示0,这样就剩些奇数个int数值来表示正整数和负整数,这意味着正的和负的int数值的数量必然不相等。这暗示着至少有一个int数值,其负值不能正确地表示成为一个int数值。

事实上,恰恰就有一个这样的int数值,它就是Integer.MIN_VALUE,即-231。他的十六进制表示是0x80000000。其符号位为1,其余所有的位都是0。如果我们对这个值取负值,那么我们将得到0x7fffffff+1,也就是0x80000000,即Integer.MIN_VALUE!换句话说,Integer.MIN_VALUE是它自己的负值,Long.MIN_VALUE也是一样。对这两个值取负值将会产生溢出,但是Java在整数计算中忽略了溢出。其结果已经阐述清楚了,即使它们并不总是你所期望的。

下面的声明将使得布尔表达式(i != 0 && i == -i)的计算结果为true,从而使循环无限环绕下去:


int i = Integer.MIN_VALUE;

下面这个也可以:


long i = Long.MIN_VALUE;

如果你对取模运算很熟悉,那么很有必要指出,这个谜题也可以用代数方法解决。Java的int算术运算是实际的算术运算对232取模的运算,因此本谜题需要一个对这种线性全等的非0解决方案:


i ≡ -i(mod 232)

将i加到恒等式的两边,我们可以得到:


2i ≡ 0(mod 32)

对这种全等的非0解决方案就是 i = 231。尽管这个值不能表示成为一个int,但是它是和-231全等的,即与Integer.MIN_VALUE全等。

总之,Java使用2的补码的算术运算,它是非对称的。对于每一种有符号的整数类型(int、long、byte和short),负的数值总是比正的数值多一个,这个多出来的值总是这种类型所能表示的最小数值。对Integer.MIN_VALUE取负值得到的还是它没有改变过的值,Long.MIN_VALUE也是如此。对Short.MIN_VALUE取负值并将所产生的int数值转型回short,返回的同样是最初的值(Short.MIN_VALUE)。对Byte.MIN_VALUE来说,也会产生相似的结果。更一般地讲,千万要当心溢出:就像狼人一样,它是个杀手。

对语言设计者的教训与谜题26中的教训一样。应该对某种溢出不会悄悄发生的整数算术运算形式提供语言级的支持。

原文地址:https://www.cnblogs.com/yuyu666/p/9840464.html

时间: 2024-10-13 04:44:57

谜题33:循环者遇到了狼人的相关文章

Java解惑三:循环之谜

谜题24 byte是有符号的,范围是-128 - 127.而0x90是int类型.比较的时候,不相等. 如果想让其相等,需要进行类型转换:(byte & 0xff) 或者 (byte)0x99. 谜题25 自增运算符对循环的影响.j = j++,先赋值. 谜题26 Integer.MAX_VALUE加一之后会变成Integer.MIN_VALUE,这对循环会有影响. 可以考虑使用long来表示i变量,或者使用效率更高的i != Integer.MAX_VALUE. 谜题27 (-1 <<

C#解惑29: 循环者的新娘

谜题29: 循环者的新娘 请提供一个对i的声明,将下面的循环转变为无限循环: while (i != i) { } 解惑29: 循环者的新娘 这个循环可能比前一个更令人困惑.不管在它前面作何种声明,它看起来确实应该立即终止.一个数字总是等于它自己,对吧? 对,但IEEE 754浮点算术保留了一个特殊的值用来表示一个不是数字的数量.这个值就是NaN("Not a Number(不是一个数字)"的缩写),对于所有没有良好的数字定义的浮点计算,例如0.0/0.0,其值都是它.规范中描述道,N

C#解惑30: 循环者的爱子

谜题30: 循环者的爱子 请提供一个对i的声明,将下面的循环转变为一个无限循环: while (i != i + 0) { } 与前一个谜题不同,你必须在答案中不使用浮点数.换句话说,你不能把i声明为double或float类型. 解惑30: 循环者的爱子 与前一个谜题一样,这个谜题初看起来是不可能实现的.毕竟,一个数字总是等于它自身加上0,你被禁止使用浮点数,因此不能使用NaN.而在整数类型中没有NaN的等价物.那么,你能给出什么呢? 我们必然可以得出这样的结论,即i的类型必须是非数值类型的,

循环数组方法

伪数组 伪数组:没有数组的方法,用数字做属性 arguments 是伪数组 arguments{ '0':11, '1':22 } arguments[0]; //访问属性0的值 或: let stu=function(){ console.log(arguments); } stu(11,22,33); // {'0':11,'1':22,'2':33} 循环数组的方法 for let ary=[100,200,300,400,500,600]; for(let i=0,i<ary.lengt

谜题86:有毒的括号垃圾

你能否举出这样一个合法的Java表达式,只要对它的某个子表达式加上括号就可以使其成为不合法的表达式,而添加的括号只是为了注解未加括号时赋值的顺序? 插入一对用来注解现有赋值顺序的括号对程序的合法性似乎是应该没有任何影响的.事实上,绝大多数情况下确实是没有影响的.但是,在两种情况下,插入一对看上去没有影响的括号可能会令合法的Java程序变得不合法.这种奇怪的情况是由于数值的二进制补码的不对称性引起的,就像在谜题33和谜题64中所讨论的那样. 你可能会联想到,最小的int型负数其绝对值比最大的int

《Java解惑》读书笔记

 摘选自<Java解惑>一书,之前整理了部分,一直没看完,最近为了督促自己每天读点这本书,决定一天至少更新一个谜题的内容,欢迎讨论. 欢迎关注技术博客http://blog.sina.com.cn/u/1822488043 Java解惑读书笔记 谜题1:奇数性 取余操作的定义: ( a / b ) * b + ( a % b ) = a 其中(a/b)是java运算的结果,也就是a/b是一个整数,比如3/2=1. 所以当取余操作返回一个非零结果的时候,它与左操作数具有相同符号. 请测试你的

Java常见问题3:周期之谜

谜24 byte是有符号的.范围是-128 - 127. 而0x90是int类型. 比較的时候.不相等. 假设想让其相等,须要进行类型转换:(byte & 0xff) 或者 (byte)0x99. 谜题25 自增运算符对循环的影响.j = j++,先赋值. 谜题26 Integer.MAX_VALUE加一之后会变成Integer.MIN_VALUE.这对循环会有影响. 能够考虑使用long来表示i变量,或者使用效率更高的i != Integer.MAX_VALUE. 谜题27 (-1 <&l

java解惑之陷阱和缺陷的目录总结

A1 词汇问题 A 1.1 字母l在许多字体中都与数字1相像 规则:在long类型字面常量中,应该总是用大写L,千万不要用小写l.不要用孤零零的一个l作为变量名. 谜题4 A 1.2 负的十六进制字面常量看起来像正的 规则: 要避免混合类型的计算.在恰当的地方要用long类型的字面常量代替int类型的字面常量.谜题5 A 1.3 八进制字面常量与十进制字面常量相像 规则: 要避免八进制字面常量.如果非得使用它们,那么请对所有用到的地方进行注释,以使得你的意图清晰. 谜题59 A 1.4 ASCI

记录实验吧 CTF库 who are you? 过程

首先我承认我看了别人怎么做的 因为我并没有什么经验虽然知道回显是由X-Forwarded-For 参数导致的 但一直无法利用 所以看了demo因为涉及到要写脚本记录注入过程 所以特此记录我看了2个demo选择了最直接的一个也就是使用awvs扫描 然后再python扫 因为我觉得我并没有手工找注入点的本事 先学学利用工具 虽然别人写了用awvs 但是开始不管怎么扫描都是扫描不出来  后来..一个简单的办法原来是这样  附图: 好简单  然后发现了果然是可以注入的 好像是基于的时间延迟 可惜没系统学