zoukankan      html  css  js  c++  java
  • 《Java从入门到失业》第三章:基础语法及基本程序结构(3.7):运算符(基本算数运算符、原码、反码、补码)

    3.7运算符

          数学运算是计算机的基本用途之一,Java提供了非常丰富的运算符来支持。我们根据运算的特点和性质,把运算符划分为几组:基本算数运算符、自增自减运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其他运算符。下面分别介绍。

    3.7.1基本算数运算符

           在Java中,采用+、-、*、/、%来表示加、减、乘、除、取余(取模),这种运算小学就学过,无需多讲,列表举例如下:

    运算

    算式

    结果(假设a=15,b=10)

    加法

    a+b

    25

    减法

    a-b

    5

    乘法

    a*b

    150

    除法

    a/b

    1

    取余

    a%b

    5

    运算非常简单,但是还是有一些问题需要注意,下面分别用实例来说明。

    3.7.1.1类型变化

      我们看一段代码:

     1 public static void main(String[] args) {  
     2         int a1 = 15;  
     3         double a2 = 15;  
     4         int b = 2;  
     5         int c = 0;  
     6         System.out.println("整数运算:");  
     7         System.out.println("a1 + b = " + (a1 + b));  
     8         System.out.println("a1 - b = " + (a1 - b));  
     9         System.out.println("a1 * b = " + (a1 * b));  
    10         System.out.println("a1 / b = " + (a1 / b));  
    11         System.out.println("a1 % b = " + (a1 % b));  
    12         System.out.println("浮点数运算:");  
    13         System.out.println("a2 + b = " + (a2 + b));  
    14         System.out.println("a2 - b = " + (a2 - b));  
    15         System.out.println("a2 * b = " + (a2 * b));  
    16         System.out.println("a2 / b = " + (a2 / b));  
    17         System.out.println("a2 % b = " + (a2 % b));  
    18     } 
     

    运行结果为:

    整数运算:  
    a1 + b = 17  
    a1 - b = 13  
    a1 * b = 30  
    a1 / b = 7  
    a1 % b = 1  
    浮点数运算:  
    a2 + b = 17.0  
    a2 - b = 13.0  
    a2 * b = 30.0  
    a2 / b = 7.5  
    a2 % b = 1.0  
     

    我们看到,整数15/2=7,而浮点数15/7=7.5。在Java中,参与运算的2个数有浮点数时,就会自动将非浮点数变成浮点数来运算。

    下面为了节省篇幅,就不再分别列出代码和结果了。

    3.7.1.2被0除问题

    0.0 / 0 = NaN  
    1.0 / 0 = Infinity  
    -1.0 / 0 = -Infinity  
    1 / 0 =   
    Exception in thread "main" java.lang.ArithmeticException: / by zero  
        at ch03.JibenYunsuanfu.main(JibenYunsuanfu.java:16) 

    我们看到,浮点数0除以0,得到NaN;正负浮点数除以0得到正负无穷大;整数除以0会抛出异常。

    3.7.1.3原码反码补码

           我们知道,Java的整型和浮点型都是有范围的,如果运算结果超过范围怎么办呢?我们知道int型的最大值是214783647,假如我们+1会得到什么结果呢?结果为:

    2147483647 + 1 = -2147483648

    说明这个问题原因之前,得先学习原码、反码、补码的相关知识。

    3.7.1.3.1原码

      我们现实生活当中,可以用正负号来表示正负数,但是计算机中只有0和1,怎么表示正负数呢?于是想出了一个办法,对于固定字长n的二进制数,把2n个数划分为正负数,把最高位规定为符号位,0代表正,1代表负,剩下的二进制数对应十进制数的绝对值。例如假设字长为3,那么一共表示8个数:

    十进制

    二进制

    3

    011

    2

    010

    1

    001

    0

    000

    -0

    100

    -1

    101

    -2

    110

    -3

    111

    这种规定叫做“原码”,即3的原码是011,-3的原码是111。看起来很完美吧,但是有2个问题:

    • 0的表示不唯一
    • 无法将减法转换为加法

    0的表示不唯一一目了然,为什么不能将减法转换为加法?我们看个例子:

    2 - 1 = 2 + (-1) = 010 + 101 = 111 = -3(正确结果为1)

    结果错误。那么又为什么要把减法转换为加法呢?我们学习过计算机组成,知道CPU中只有加法寄存器,因为计算机中处理加法比较简单,如果要直接处理减法,需要增加逻辑部件,而且处理减法有借位问题很麻烦。因此在计算机中用原码来进行运算和存储行不通。

    3.7.1.3.2反码

           还有别的办法吗?人们又发明了“反码”。反码规定:正数的反码和原码一致,负数的反码为该数对应的绝对值的原码按位取反。假设字长为3,原码反码分别如下:

    十进制

    原码

    反码

    3

    011

    011

    2

    010

    010

    1

    001

    001

    0

    000

    000

    -0

    100

    111

    -1

    101

    110

    -2

    110

    101

    -3

    111

    100

    反码解决了减法转换为加法的问题,但是额外需要多一个规定,就是当发生溢出时,需要对最低位加1。我们看2个例子:

    1 – 1 = 1 + (-1) = 001 + 110 = 111 =-0
    2 - 1 = 2 + (-1) = 010 + 110 = 1000,溢出了,去掉溢出位后需再加1即000 + 001 = 001 = 1

    我们看到,结果都正确。但是还是存在2个问题:

    • 0的表示不唯一
    • 减法转加法,需要判断溢出问题

    3.7.1.3.3补码

    继续探讨,于是出现“补码”。补码规定正数的补码和原码一致,负数的补码为该数对应的绝对值按位取反后加1(如果溢出丢弃最高位)

    十进制

    原码

    反码

    补码

    3

    011

    011

    011

    2

    010

    010

    010

    1

    001

    001

    001

    0

    000

    000

    000

    -0

    100

    111

    000

    -1

    101

    110

    111

    -2

    110

    101

    110

    -3

    111

    100

    101

    我们发现0的表示唯一了。另外用补码计算减法也很简单了,直接转换即可(溢出直接丢弃最高位),我们看2个例子:

    1 – 1 = 1 + (-1) = 001 + 111 = 1000 = 000 = 0
    2 - 1 = 2 + (-1) = 010 + 111 = 1001 = 001 = 1

    喜欢钻牛角尖的同学就会问了,为什么使用补码就可以解决这些问题呢?有什么道理吗?我就知道你会问,还好我也恶补了这段知识,下面我们来研究一下。

    3.7.1.3.4补码原理

           我们知道,对于一个3位的二进制,对应的十进制为0-7,一共8个。7+1=111+000=1000,去掉溢出位,又变成000即0。我们可以说这8个数字形成了一个闭环。这其实对应数学中的一个概念:模。

      模是指一个计量系统的计数范围,例如我们熟悉的时钟,它的计数范围是0-11,模是12。计算机也可以看成一个计量机器,因为计算机的字长是定长的,即存储和处理的位数是有限的,因此它也有一个计量范围,即都存在一个“模”。对于字长3位的机器来说,计数范围是0-7,模是8。“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为加法运算。

      我们以时钟为例:当前时间是2点,逆时针拨2格变成0点。顺时针拨10格也是0点。假设逆时针叫减,顺时针叫加,那么对于模12的系统里,减2和加10的效果一样。事实上,减3和加9,减4和加8效果也一样。我们把2和10、3和9、4和8互称为补数,特点就是二者相加等于模。因此在有模的系统里,减去一个数,可以变成加上它的补数,即可以把减法变成加法。

    回到3位数的二进制如下图:

    我们很容易就知道模为8,1和7、2和6、3和5、4和4他们互为补数。列一个表:

    减数

    补数

    1

    7

    2

    6

    3

    5

    4

    4

    5

    3

    6

    2

    7

    1

    但是问题来了,3位二进制系统里,虽然减n可以变成加n,但是由于没有负数,因此计算减法,需要先计算减数的补数,例如减1,需要计算1的补数8-1。怎么办?聪明的你一定可以想到,补数都是成对的,我们把成对的补数中的一半规定为负数是不是就可以了?例如a-1=a+(-1)=a+7,假如我们规定7的二进制111代表-1,那么在计算的时候就没有减法了。同理我们还可以规定110代表-2,101代表-3。至于100是代表4还是-4,都可以,一般我们选择代表-4。这样一来,对于3位二进制系统,表示数的范围就变成-4~3,而所有的减法就变成加法了。而且这样一来我们还惊奇的发现:

    • 所有的正数最高位都是0,负数最高位都是1
    • 所有负数的二进制都是它所对应的绝对值的二进制按位取反后+1,就是补码

    到此为止,我们就搞清楚了为什么在计算中要用补码来表示负数了。

      最后,我们回到开头的例子:

    2147483647 + 1 = -2147483648 

    现在回答这个问题太easy了。在Java中,一个数字如果不加后缀,默认就是int型的。我们知道int型占用4个字节,则int的系统是一个模为232的系统。然后采用补码规则存储,这样最大的正数是231-1=2147483647。这个数再加1就变成231。231的补数是它自己,但是由于231的二进制最高位是1,我们习惯把它规定为负数,即-231,因此就是-2147483648。

  • 相关阅读:
    Ajax实现表格实时编辑
    自定义简单分页
    有趣的 0
    关于AJAX的一些事
    JQ中的FormData对象 ajax上传文件
    订单导出
    javaScript事件委托
    javascript递归函数
    详解javascript中this的工作原理
    详解JavaScript对象继承方式
  • 原文地址:https://www.cnblogs.com/javadss/p/13537348.html
Copyright © 2011-2022 走看看