Java中byte类型的取值范围
取值范围为-128~127
1.为什么是[-128,127]
  计算机中存储最⼤的应该是0111 1111,第⼀位是符号位,所以表⽰最⼤的数值:127
  存储的1 1111111应该是最⼩的数值:-127
  范围按照这样应该取的是[-127,127],怎么会是-128~127呢,下⾯我们来探讨⼀下。
  在解释这个问题之前我们需要了解⼏个概念:机器数、真值、原码、反码、补码
机器数
⼀个数在计算机中的⼆进制表⽰形式, 叫做这个数的机器数。机器数是带符号的,在计算机⽤⼀个数的最⾼位存放符号, 正数为0, 负数为1。
⽐如:⼗进制中的数 +3 ,计算机字长为8位,转换成⼆进制就是00000011。如果是 -3 ,就是 1 0000011 。那么,这⾥的00000011 和 10000011 就是机器数。
真值
因为第⼀位是符号位,所以机器数的形式值就不等于真正的数值。
  例如上⾯的有符号数 1 0000011,其最⾼位1代表负,其真正数值是 -3 ⽽不是形式值131(10000011转换成⼗进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1 000 0001的真值 = –000 0001 = –1
原码
  原码就是符号位加上真值的绝对值, 即⽤第⼀位表⽰符号, 其余位表⽰值. ⽐如如果是8位⼆进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
  因为第⼀位是符号位, 所以8位⼆进制数的取值范围就是:[1111 1111 , 0111 1111]
即[-127 , 127]。原码是⼈脑最容易理解和计算的表⽰⽅式.
反码
  反码的表⽰⽅法是:正数的反码是其本⾝,负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [1 1111110]反
  可见如果⼀个反码表⽰的是负数, ⼈脑⽆法直观的看出来它的数值. 通常要将其转换成原码再计算.
补码
补码的表⽰⽅法是:
正数的补码就是其本⾝
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [1 1111111]补
对于负数, 补码表⽰⽅式也是⼈脑⽆法直观看出其数值的. 通常也需要转换成原码在计算其数值.
正数:
正数的反码和补码都与原码相同
负数:
负数的反码、补码与原码不同,负数的反码:原码中除去符号位,其他的数值位取反,0变1,1变0。负数的补码:反码+1例如:
2.为什么byte类型的取值范围为-128~127?
  计算机可以有三种编码⽅式表⽰⼀个数. 对于正数因为三种编码⽅式的结果都相同:
[+1] = [00000001]原 = [00000001]反 = [00000001]补
所以不需要过多解释. 但是对于负数:
[-1] = [10000001]原 = [11111110]反 = [11111111]补
  可见原码, 反码和补码是完全不同的. 既然原码才是被⼈脑直接识别并⽤于计算表⽰⽅式, 为何还会有反码和补码呢?
  ⾸先, 因为⼈脑可以知道第⼀位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. 但是对于计算机, 加减乘除已经是最基础的运算, 要设计的尽量简单. 计算机辨别”符号位”显然会让计算机的基础电路设计变得⼗分复杂! 于是⼈们想出了将符号位也参与运算的⽅法. 我们知道, 根据运算法则减去⼀个正数等于加上⼀个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法⽽没有减法, 这样计算机运算的设计就更简单了.
  于是⼈们开始探索 将符号位参与运算, 并且只保留加法的⽅法. ⾸先来看原码:
  计算⼗进制的表达式: 1-1=0
  1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
  如果⽤原码表⽰, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使⽤原码表⽰⼀个数.
  为了解决原码做减法的问题, 出现了反码:
  计算⼗进制的表达式: 1-1=0
  1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
  发现⽤反码计算减法, 结果的真值部分是正确的. ⽽唯⼀的问题其实就出现在”0”这个特殊的数值上. 虽然⼈们理解上+0和-0是⼀样的,但是0带符号是没有任何意义的. ⽽且会有[0000 0000]原和[1000 0000]原两个编码表⽰0.
  于是补码的出现, 解决了0的符号以及两个编码的问题:
  1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 =[0000 0001]反 + [1111 1110]反= [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
这样0⽤[0000 0000]表⽰, ⽽以前出现问题的-0则不存在了.⽽且可以⽤[1000 0000]表⽰-128:
  (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
  -1-127的结果应该是-128, 在⽤补码运算的结果中, [1000 0000]补码就是-128. 但是注意因为实际上是使⽤以前的-0的补码来表⽰-128, 所以-128并没有原码和反码表⽰.(对-128的补码表⽰[1000 0000]补算出来的原码是[0000 0000], 这是不正确的),使⽤补码, 不仅仅修复了0的符号以及存在两个编码的问题, ⽽且还能够多表⽰⼀个最低数. 这就是为什么8位⼆进制, 使⽤原码或反码表⽰的范围为[-127, +127], ⽽使⽤补码表⽰的范围为[-128, 127]。
3131负数二进制补码运算法则
  因为机器使⽤补码, 所以对于编程中常⽤到的32位int类型, 可以表⽰范围是: [-2, 2-1] 因为第⼀位表⽰的是符号位.⽽使⽤补码表⽰时⼜可以多保存⼀个最⼩值。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。