首页 > 编程知识 正文

计算机基础原码反码补码,原码运算

时间:2023-05-04 12:17:47 阅读:174677 作者:1288

注:我以前找过有关源代码、反码、补码的资料,是一家过时的酒馆的博客。 源代码、逆向代码和补充代码都有详细说明。 为了方便,此处转载,著作权归原作者所有。 更深入的分析,可以参考作者的原文。

正文大部分来自这里。 接下来我将为本人补充一小部分“多数溢出”问题。

机器数量和真值

机器的数量

数在计算机中的二进制表示,称为此数的机器数。 机器的数量有符号,由计算机用一个数量的最高有效位存储符号,正数为0,负数为1

例如,十进制数中的数3,计算机的字长为8位,转换为二进制数时为00000011。 -3表示10000011。 那么,这里的0000011和10000011是机器数量。

真值

第一位是符号位,因此机器数量的型号值不等于真数值。 例如,上面的符号10000011的最高有效位1表示负,其真值为-3而不是形式值131。 (10000011转换为十进制后就是131。 因此,为了进行区分,将与有符号位的装置数相对应的真数值称为装置数的真值。

例如: 0000 0001的真值=000001=1,10000001的真值=-000 0001=-1

原始代码

原代码是在符号位上加上真值的绝对值后的代码,即用第一个位表示符号,用剩馀的位表示值。例如,如果是8位二进制,则为:

[ 1]原=0000 0001

[-1]原=1000 0001

第一位是符号位。 因为第一位是符号位,所以8位二进制数的可取范围为:

[ 1111111,01111111 ],即:

[-127,127 ]

源代码是人脑最容易理解和计算的表示方式。

反码

反码显示方法是正数的反码本身; 的反码基于其原始代码,符号位不变,其余各位相反。

[ 1]=[00000001]原=[00000001]反

[-1]=[10000001]原=[11111110]反

如果反码表示负数,人脑就无法直观地看到该数值。 通常将其转换为原始代码进行计算。

补充代码

补数显示方法是正数的补数本身; 的补数,根据其原始代码,符号的位数不变,剩下的各位取反,最后1.(即根据反码1 ) ) )。

[ 1]=[00000001]原=[00000001]反=[00000001]补

[-1]=[10000001]原=[ 111111110 ]反=[11111111]补

对于负数,补数的表示方法人脑也无法直观地识别该数值。通常需要转换成原来的代码计算该数值。

为什么要用原码、反码、补码呢

在开始深入学习之前,我的学习建议首先是“死记硬背”上的源代码、反码和辅助码的表示方法和计算方法。

据了解,目前计算机上可以用3种编码方式表示1个数据。 关于正数,这是因为3种编码方式的结果都是相同的:

[ 1]=[00000001]原=[00000001]反=[00000001]补

所以,没有必要解释太多。 但是,关于负:

[-1]=[10000001]原=[ 111111110 ]反=[11111111]补

可见源代码与反码和补码完全不同.源代码才是人脑直接识别并用于计算显示的,为什么会有反码和补码呢?

首先,人脑可以知道第一位是符号位,所以计算时根据符号位,选择真值区域的加减。 ()真值的概念在本文的开头)。 但是在计算机中,加减乘数已经是最基础的运算,需要尽量简单地设计。 计算机分辨“符号位”显然使计算机的基础电路设计非常复杂。 因此,提出了符号位也参加运算的方法。根据运算法则减去正数,就会加上:1-1=1(1(-1 )=0这样的负数,所以机器可以不进行减法运算而只进行加法运算,计算机运算的设计更好

于是,人们开始寻找使符号位参与运算,只保留加法的方法。 首先看源代码。 要计算十进制数的表达式: 1-1=0

1-1=1(-1 )=[00000001]原([ 100000001 ] )原=[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 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].

因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

补码表示的溢出问题

以下是本人的补充的理解,不知道是否正确:

由于计算机中的数字用补码表示,例如8bit的byte类型的表示范围为:

[-128, 127]

0 = [0000 0000](补)

-128 = [1000 0000](补)

127 = [0111 1111](补)

当byte类型的变量超上限127时,如:

+128 = -(-128)= 127 + 1

= [1111 1111](补)+ [0000 0001](补)

= [1000 0000](补)

= -128

+129 = 127 + 2

= [1111 1111](补)+ [0000 0001](补)

= [1000 0001](补)

= [1111 1111](原)

= -127

当byte类型的变量超过下限-128时:

-129 = -128 - 1

= [1000 0000](补) - [0000 0001](补)

= [0111 1111](补)

= 127

-130 = -128 - 2

= [1000 0000](补) - [0000 0010](补)

= [0111 1110](补)

= 126

byte a = -128, b = (byte) 128, c = (byte) 129, d = (byte) 130;

byte e = (byte) -129, f = (byte) -130;

System.out.println(a == ((byte)-a)); // true

System.out.println(b); // -128

System.out.println(c); // -127

System.out.println(d); // -126

System.out.println(e); // 127

System.out.println(f); // 126

1

2

3

4

5

6

7

8

大数溢出问题

int类型在32位系统中占4个字节、32bit,补码表示的的数据范围为:

[10000000 00000000 00000000 00000000] ~ [01111111 11111111 11111111 11111111]

[−231,231−1][−231,231−1]

[-2147483648, 2147483647]

在java中表示为:

[Integer.MIN_VALUE, Integer.MAX_VALUE]

与byte类型的表示一样,由于负数比正数多表示了一个数字。对下限去相反数后的数值会超过上限值,溢出到下限,因此下限的相反数与下限相等;对上限去相反数的数值为负值,该负值比下限的负值大1,在可以表示的范围内,因此上限的相反数是上限直接取负值。

// 2147483647 [01111111 11111111 11111111 11111111]

System.out.println(Integer.MAX_VALUE);

// -2147483648 [10000000 00000000 00000000 00000000]

System.out.println(Integer.MIN_VALUE);

// -2147483647 正常

System.out.println(-Integer.MAX_VALUE);

// -2147483648 2147483648,超过上限,发生溢出

System.out.println(-Integer.MIN_VALUE);

// true,2147483648 发生溢出

// 对下限去相反数后的数值会超过上限值,溢出到下限,因此下限的相反数与下限相等

System.out.println((Integer.MIN_VALUE == -Integer.MIN_VALUE));

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

这个特点在进行大数溢出判断时会用到,例如JKD源码中字符串转化为int类型的函数,Integer.parseInt(String str)中,只能使用对上限取反Integer.MAX_VALUE当成负数累减,而不能对下限取反Integer.MIN_VALUE当成正数累加。

Integer.parseInt(String str)源码:

public static int parseInt(String s) throws NumberFormatException {

return parseInt(s,10);

}

// radix是进制表示

public static int parseInt(String s, int radix)

throws NumberFormatException

{

/*

* WARNING: This method may be invoked early during VM initialization

* before IntegerCache is initialized. Care must be taken to not use

* the valueOf method.

*/

if (s == null) {

throw new NumberFormatException("null");

}

if (radix < Character.MIN_RADIX) {

throw new NumberFormatException("radix " + radix +

" less than Character.MIN_RADIX");

}

if (radix > Character.MAX_RADIX) {

throw new NumberFormatException("radix " + radix +

" greater than Character.MAX_RADIX");

}

int result = 0;

boolean negative = false;

int i = 0, len = s.length();

int limit = -Integer.MAX_VALUE; // 对上限取反不会溢出

int multmin;

int digit;

if (len > 0) {

char firstChar = s.charAt(0);

if (firstChar < '0') { // Possible leading "+" or "-"

if (firstChar == '-') {

negative = true;

limit = Integer.MIN_VALUE;

} else if (firstChar != '+')

throw NumberFormatException.forInputString(s);

if (len == 1) // Cannot have lone "+" or "-"

throw NumberFormatException.forInputString(s);

i++;

}

multmin = limit / radix;

while (i < len) {

// Accumulating negatively avoids surprises near MAX_VALUE

digit = Character.digit(s.charAt(i++),radix);

if (digit < 0) {

throw NumberFormatException.forInputString(s);

}

// 除以10必须放在不等式右侧防止左侧溢出

// 如果满足条件,说明 result*radix不会发生溢出

if (result < multmin) {

throw NumberFormatException.forInputString(s);

}

result *= radix;

// digit必须放在不等式右侧防止左侧溢出,判断防止最终溢出

// 如果满足条件说明 result-digit不会发生溢出

if (result < limit + digit) {

throw NumberFormatException.forInputString(s);

}

// 当成负数累减

result -= digit;

}

} else {

throw NumberFormatException.forInputString(s);

}

return negative ? result : -result;

}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。