黑马程序员技术交流社区

标题: 逆袭了,负数的绝对值是负数 [打印本页]

作者: 贾文泽    时间: 2013-2-26 20:07
标题: 逆袭了,负数的绝对值是负数
看这段代码
  1. int a=-2147483648;   //int类型的最小负整数
  2. System.out.println(Math.abs(a));
复制代码
输出:-2147483648

小学数学老师都错啦,真要逆袭了,原来负数的绝对值可以是负数
作者: Rancho_Gump    时间: 2013-2-26 20:09
有意思 {:soso_e113:}
作者: 黑马刘杰    时间: 2013-2-26 20:30
-2147483648的正数是+2147483648,但是int类型的有符号数最大值就是2147483647,这儿溢出了,所以整型的最小值没有绝对值。
作者: 王昕    时间: 2013-2-26 20:47
和2147483647+1是-2147483648一样,32位有符号整数的补码表示嘛。
作者: 贾文泽    时间: 2013-2-26 20:52
黑马刘杰 发表于 2013-2-26 20:30
-2147483648的正数是+2147483648,但是int类型的有符号数最大值就是2147483647,这儿溢出了,所以整型的最 ...

你听过整数会溢出么?整数是不会溢出的,整数的溢出被认为是正常的舍弃,
但是实际就是这个数的绝对值就等于他自己本身
作者: 贾文泽    时间: 2013-2-26 20:53
张向辉 发表于 2013-2-26 20:09
有意思

:loveliness: 有意思,留下技术分再飘过
作者: Rancho_Gump    时间: 2013-2-26 21:23
贾文泽 发表于 2013-2-26 20:53
有意思,留下技术分再飘过

哎~  对文泽兄必须严厉要求  怎能轻易给分 ;P
作者: Rancho_Gump    时间: 2013-2-26 21:26
再补一句,JAVA就是这么设计的。记住这个有意思的小知识就好了。
作者: 贾文泽    时间: 2013-2-26 21:40
张向辉 发表于 2013-2-26 21:23
哎~  对文泽兄必须严厉要求  怎能轻易给分

当你发现你写的程序中 0.2+0.4 输出的并不是0.6的时候
当你发现你写的程序中 String s = a+b+c+d+e;  真正是创建了三个对象的时候
当你发现你写的程序中 0.1*10 能输出1.0 但是10个0.1相加输出的并不是1.0的时候

当你发现,这世界上只有10种人,一种是懂二进制的人,一种是不懂二进制的人
这时候其实你是中邪了,唯有给我多加点分,才能解脱;P
作者: Rancho_Gump    时间: 2013-2-26 21:46
贾文泽 发表于 2013-2-26 21:40
当你发现你写的程序中 0.2+0.4 输出的并不是0.6的时候
当你发现你写的程序中 String s = a+b+c+d+e;  真 ...

当你发现你写的程序中 String s = a+b+c+d+e;  真正是创建了三个对象的时候
这句有点不懂,莫非真中邪了 :lol
作者: 贾文泽    时间: 2013-2-26 22:14
本帖最后由 贾文泽 于 2013-2-26 22:17 编辑
张向辉 发表于 2013-2-26 21:46
当你发现你写的程序中 String s = a+b+c+d+e;  真正是创建了三个对象的时候
这句有点不懂,莫非真中邪了  ...

加分就会自动解咒的{:soso_e113:}
String s = a+b+c+d+e;
由于编译器的优化,最终代码为通过StringBuilder完成:
  1. StringBuilder builder = new StringBuilder();
  2. builder.append(a);
  3. builder.append(b);
  4. builder.append(c);
  5. builder.append(d);
  6. builder.append(e);
  7. String s = builder.toString();
复制代码
StringBuilder的构造器是这样的
  1. public StringBuilder() {
  2.       super(16);              //这里其实是  value =new char[capacity];
  3.     }
复制代码
这样就分配了一个16个长度的数组(数组也是一个对象吧)
append里面使用了arraycopy的复制方式,也没有产生新的对象。再看StringBuilder的 toString()方法:
  1. public String toString() {
  2.     // Create a copy, don't share the array
  3.     return new String(value, 0, count);                   //生成一个新的String ,算是一个对象吧
  4.   }
复制代码
所以真正的是创建了3个对象,但是只有一个是String对象
1 StringBuilder
2 new char[capacity]
3 new String(value,0,count);

但是,如果超过了16个字节的长度,append里面就不再使用arraycopy了,而是Arrays,,,这样会再创建一个数组的



作者: HM王琦    时间: 2013-2-27 00:47
学习了

作者: 贾文泽    时间: 2013-2-27 03:25
[野狼]~@ 发表于 2013-2-27 00:47
学习了

:L 野狼?  啊,,野狼?  小生?
作者: 王宝生    时间: 2013-2-27 08:47
标题: RE: 逆袭了,负数的绝对值是负数
   int的取值范围是不对称的,他最小值是 -2147 483 648(ox8000 0000),最大值是2147 483 647(0x7FFF FFFF).
   这时最小值的绝对值是2147483 648,这不在int的范围之内啊,所以肯定会产生溢出。
   对于溢出为什么正变负,负变正,你可以参考下
    图:
从这个图中可以看出,int的最大值如果产生溢出就会变成int的最小值,也就是如果你计算2147 483 647+1,结果会是-2147 483 648。同理,int的最小值产生溢出也会变成整数,例如-2147 483 647-1=2147 483 647

    那么对于绝对值来说,当Math.abs检测到结果可能为溢出时,他就什么都不会做而是直接给出原数。因为如果他真要进行绝对值处理,结果肯定不是正确的,这只会让人更加迷惑。对于其他语言基本上也是采取类似的情况,C/c++和java中一样。而在C#中则会抛出一个异常。

我再多说一点,对于有符号数来说,可能会产生溢出,对于无符号数来说,我们一般不称其为溢出,而是进位,此时的结果是正常的。

有符号溢出.jpg (13.94 KB, 下载次数: 65)

有符号溢出.jpg

作者: 贾文泽    时间: 2013-2-27 10:42
王宝生 发表于 2013-2-27 08:47
int的取值范围是不对称的,他最小值是 -2147 483 648(ox8000 0000),最大值是2147 483 647(0x7FFF FF ...

我可以很明确的说整数是不存在溢出的,整数的溢出被视为正常的舍弃
是这个数的绝对值本来就是他本身
绝对值怎么定义的?     (x>=0)? x : -x       也就是说如果x为负数,那x的绝对值就是 -x   这点你没意见吧
那绝对值在计算机内部就是 补码全部取反+1  
这个数的补码全部取反+1 还是他自己本身
作者: Rancho_Gump    时间: 2013-2-27 11:03
贾文泽 发表于 2013-2-26 22:14
加分就会自动解咒的
String s = a+b+c+d+e;
由于编译器的优化,最终代码为通过StringBuilde ...

这个知识点值得学习 必须赞一个!加1分!
然诅咒版主之行为,扣2分! :lol
作者: 黄嵘才    时间: 2013-2-27 11:25
知识点细致丰富,谢谢分享。
作者: 颜春    时间: 2013-2-27 11:43
这是因为整数在内存中使用的是补码的形式表示,最高位是符号位,0表示正数,1表示负数:
例如一个8位的整数
正数的补码:为这个数的2进制码,例如3:0000 0101
负数的补码:为这个负数的绝对值的2进制码,取反加1,例如-3:
   a: 3的2进制码取反为: 1111 1010
   b: 加1:1111 1011
   c: 所以-3的补码是:1111 1011

从补码计算这个数:
从一个正数的补码计算这个正数,例如0000 0101:因为符号位是0,所以是正数,所以直接计算这个正数就行了,所以结果是 3

从一个负数的补码计算这个负数,例如-3:1111 1011:
   a: 因为符号位(最高位)为1,所以表示这个数是负数
   b: 用补码取反加1为这个负数的绝对值整数值:0000 0100 + 1 => 0000 0101 => 3
   c: 所以1111 1011的值为-3

例如:
   byte b = 127;
   b = (byte) (b + 1);
最后b的值是多少?
   127的二进制为: 0111 1111
   127+1则为:0111 1111 + 1 = 1000 0000
所以当计算1000 0000的值时,
   a: 最高位为1,所以是负数
   b: 取反加1:0111 1111 + 1 = 1000 0000
   c: 计算1000 0000的值:128
   d: 结果:128的负值,所以为-128,即byte类型的127加1的值为-128
作者: 贾文泽    时间: 2013-2-27 14:02
颜春 发表于 2013-2-27 11:43
这是因为整数在内存中使用的是补码的形式表示,最高位是符号位,0表示正数,1表示负数:
例如一个8位的整数 ...

从一个负数的补码计算这个负数,例如-3:1111 1011:
   a: 因为符号位(最高位)为1,所以表示这个数是负数
   b: 用补码取反加1为这个负数的绝对值整数值:0000 0100 + 1 => 0000 0101 => 3
   c: 所以1111 1011的值为-3

上面的算法你确定你算的正确?
-3    原码:   1000 0011
       符号位不变,其他位取反+1 得到补码   : 1111 1100+1  ---->  1111 1101
求绝对值:   补码全部取反+1    :   0000 0010+1  ----->   0000 0011

最后得到的补码是 0000 0011  符号位是0,整数的原码,补码,反码都一样,那补码是0000 0011的是不是就是3
作者: 贾文泽    时间: 2013-2-27 14:11
张向辉 发表于 2013-2-27 11:03
这个知识点值得学习 必须赞一个!加1分!
然诅咒版主之行为,扣2分!  ...

:(咱们京城见,你对我的好我会好好都记小本本上的
作者: Rancho_Gump    时间: 2013-2-27 15:03
贾文泽 发表于 2013-2-27 14:11
咱们京城见,你对我的好我会好好都记小本本上的


嗯 京城见哦  :lol  
作者: zjkal    时间: 2013-2-28 13:20
mark,学习了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2