banner
NEWS LETTER

2-补码加减乘除

Scroll down

一. 计算两个32位二进制整数补码真值的和

1. 步骤

  1. 初始化:将 src 和 dest 转换为字符串形式,并初始化一个 StringBuilder 来存储结果。
  2. 逐位相加:从最低位(第31位)开始逐位相加,考虑进位情况
  3. 处理进位:根据当前位的和以及是否有进位,决定当前位的结果和是否产生新的进位
  4. 结果反转:由于结果是从最低位开始添加的,最终需要反转字符串以得到正确的顺序
  5. 返回结果:将结果转换为 DataType 并返回。
    • DataType ans = new DataType(ansStr);

2. 【注意】结果反转

  • String ans = ansStr.reverse().toString();
  • StringBulider才能用.reverse(); String不能用

3. 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public DataType add(DataType src, DataType dest) {
String srcStr=src.toString();
String destStr=dest.toString();
StringBuilder ansStr = new StringBuilder();
boolean carry = false;
for(int i=31;i>=0;i--) {
int destInt = destStr.charAt(i) - '0';
int srcInt = srcStr.charAt(i) - '0';
if (!carry) {//无进位
if (destInt + srcInt == 2) {
carry = true;
ansStr.append(0);
} else if(destInt+srcInt==1){
ansStr.append(1);
}else{
ansStr.append(0);
}
}else{//有进位
if (destInt + srcInt == 2) {
ansStr.append(1);
} else if(destInt+srcInt==1){
ansStr.append(0);
}else{
ansStr.append(1);
carry=false;
}
}
}
DataType ans = new DataType(ansStr.reverse().toString());
return ans;
}

4. 更简单:

  • int sum = num1 + num2 + carry;
  • result.append(sum % 2);
  • carry = sum / 2;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public DataType add(DataType src, DataType dest) {
StringBuilder result = new StringBuilder();
String srcStr = src.toString();
String destStr = dest.toString();
int carry = 0;
for (int i = 31; i >= 0; i--) {
int num1 = srcStr.charAt(i) - '0';
int num2 = destStr.charAt(i) - '0';
int sum = num1 + num2 + carry;
result.append(sum % 2);
carry = sum / 2;
}
return new DataType(result.reverse().toString());
}

二、计算两个32位二进制整数补码真值的差

  • dest表示被减数,src表示减数(即计算dest - src)

1. 取反操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public String negation(String beforeStr){
StringBuilder afterStr = new StringBuilder();
//逐位取反
for(int i=0;i<32;i++){
if (beforeStr.charAt(i)=='0'){
afterStr.append('1');
}else{
afterStr.append('0');
}
}
//加1
boolean carry = true;
for(int i=31;i>=0;i--){
if(carry){//有进位
if(afterStr.charAt(i)=='0'){
afterStr.replace(i,i+1,"1");
carry=false;
}else{
afterStr.replace(i,i+1,"0");
}
}
}
return afterStr.toString();
}

2.完整代码

1
2
3
4
5
6
public DataType sub(DataType src, DataType dest) {
String srcStr=src.toString();
srcStr=negation(srcStr);
src = new DataType(srcStr);
return add(src,dest);
}

三、两个二进制整数的乘积(布斯乘法,结果低位截取后32位)

1.布斯乘法

  1. 正负数处理:
    • 检查 src 和 dest 是否为负数,如果是负数,则将其转换为正数
  2. 初始化:
    1. 初始化 resultStr65位字符串,其中前32位为0,后32位为 dest,并在末尾添一个0
      • 32个0+dest+0
  3. 迭代计算:
    • 对 resultStr 进行32次迭代;第一次是0-最低位
    • 每次根据 resultStr 的最低位和次低位的组合(最低位-次低位)决定是否进行加法或减法操作。
      • 如果组合为 01(1),则将 resultStr的高32位 + src
      • 如果组合为 10(-1),则将resultStr的高32位 - src
      • 如果组合为 11或00(0),则不变。
      • 进行算术右移操作(保留符号位)
  4. 重复:
    • 重复上述迭代步骤,直到处理完乘数的所有位。
  5. 结果:
    • 截取 resultStr 的**低32位(33~64)**作为最终结果
    • 如果原始 src 和 dest 中有一个是负数,则将结果取反。

2. 算术右移方法:

  1. 符号位不变
  2. 原本的64位整体右移
  • 相当于前面变成两个符号位,最后一位丢掉

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public DataType mul(DataType src, DataType dest) {
String srcStr=src.toString();
String destStr = dest.toString();
//1.判断正负,如果负,则标记并转为正
boolean srcNeg=false;
boolean destNeg=false;
if(srcStr.charAt(0)=='1'){
srcNeg=true;
srcStr=negation(srcStr);
}
if(destStr.charAt(0)=='1'){
destNeg=true;
destStr=negation(destStr);
}

//2.初始化
StringBuilder resultStr=new StringBuilder("0".repeat(32)+destStr+"0");//result,32个0+dest+0组成
//3.计算
for(int i=32;i>0;i--){
DataType src1=new DataType(srcStr);
DataType dest1=new DataType(resultStr.substring(0,32));

if(i==32){//第1位(补充了一个0)
if(destStr.charAt(31)-'0'==0){//0:右移
resultStr= new StringBuilder(rightshift(resultStr.toString()));//右移
continue;
}else{//-1:减src,再右移
resultStr.replace(0,32,sub(src1,dest1).toString());
resultStr= new StringBuilder(rightshift(resultStr.toString()));//右移
}
}else{//其它位
if(destStr.charAt(i)-destStr.charAt(i-1)==0){//0:右移
resultStr= new StringBuilder(rightshift(resultStr.toString()));//右移
continue;
}else if(destStr.charAt(i)-destStr.charAt(i-1)==1){//1:加src,再右移
resultStr.replace(0,32,add(src1,dest1).toString());
resultStr= new StringBuilder(rightshift(resultStr.toString()));//右移
}else{//-1:减src,再右移
resultStr.replace(0,32,sub(src1,dest1).toString());
resultStr= new StringBuilder(rightshift(resultStr.toString()));//右移
}
}

}
//4.结果:截取低32位
String result=resultStr.substring(32,64);
//正负调整
if((srcNeg&&!destNeg)||(!srcNeg&&destNeg)){
result =negation(result);
}
return new DataType(result);
}

public String rightshift(String beforeStr){//右移
StringBuilder afterStr = new StringBuilder();
afterStr.append(beforeStr.charAt(0));//保留符号位
for(int i=0;i<64;i++){
afterStr.append(beforeStr.charAt(i));
}
return afterStr.toString();
}

四、两个二进制整数的除法

  • 恢复余数除法不恢复余数除法均可
  • dest ÷ src
  • 将32位余数正确储存在余数寄存器remainderReg中
  • 除数为0,且被除数不为0时要求能够正确抛出ArithmeticException异常

1. 恢复余数除法

  1. (此代码中)正负调整(【Datatype】src和【String】srcStr都要)
  2. 初始化:
    • 被除数(Dividend)和除数(Divisor)分别存储在寄存器中。
    • 余数寄存器(Remainder)初始化为32位的0
    • 寄存器(Quotient)初始化为被除数
  3. 迭代:对被除数的每一位进行处理,从最高位到最低位
    1. 余数左移一位,并将被除数的当前位移入余数的最低位
    2. 余数减去/加上除数
      • 如果余数与原本异号,则恢复余数(加回除数),并将商的当前位设为0
      • 如果余数与原本同号,则将商的当前位设为1
  4. 结果:
    • (此代码中)调整余数和商的符号
    • 迭代完成后,商寄存器中存储的值即为商,余数寄存器中存储的值即为余数。

2. 不恢复余数除法

  1. 初始化:
    • 被除数(Dividend)和除数(Divisor)分别存储在寄存器中。
    • 余数寄存器(Remainder)初始化为0。
    • 商寄存器(Quotient)初始化为被除数。
  2. 迭代: 对被除数的每一位进行处理,从最高位到最低位。
    1. 余数左移一位,并将被除数的当前位移入余数的最低位
    2. 余数减去/加上除数。
      • 如果余数与原本异号,则将商的当前位设为0,并在下一次迭代中将余数加回除数
      • 如果余数与原本同号,则将商的当前位设为1,并在下一次迭代中继续减去除数
  3. 结果:
    • 根据被除数和除数的符号,调整商和余数的符号:
      • 被除数和除数同号:余数+除数,商为正
      • 被除数和除数异号:余数-除数,商为负
    • 迭代完成后,商寄存器中存储的值即为商,余数寄存器中存储的值即为余数。

3. 调整余数和商的符号

  1. 余数和被除数同号
  2. 其中一方为负,则商取负

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
DataType remainderReg;

/**
* 返回两个二进制整数的除法结果
* dest ÷ src
*
* @param src 32-bits
* @param dest 32-bits
* @return 32-bits
*/
//用恢复余数除法
public DataType div(DataType src, DataType dest) {
String srcStr = src.toString();
String destStr = dest.toString();
//0.判断除0情况
if(srcStr.equals("00000000000000000000000000000000")){
throw new ArithmeticException("除0");
}

//1. 判断正负,如果是负就转正,并标记
boolean srcNeg=false;
boolean destNeg = false;
if(srcStr.charAt(0)=='1'){
srcStr=negation(srcStr);
src=new DataType(srcStr);//保证src也变号
srcNeg=true;
}
if(destStr.charAt(0)=='1'){
destStr=negation(destStr);
dest = new DataType(destStr);//保证dest也变号
destNeg=true;
}
//2. 初始化-商和余数寄存器
StringBuilder Shang=new StringBuilder(destStr);//商,初始化为被除数
StringBuilder Yu = new StringBuilder("0".repeat(32));//余数,初始化为32个0
//3. 计算
for(int i=0;i<32;i++){
//3.1左移
Yu=leftshift(Yu.toString());
Yu.append(Shang.charAt(0));
Shang=leftshift(Shang.toString());
//3.2 余数减去除数
String tmp=sub(src,new DataType(Yu.toString())).toString();
if(tmp.charAt(0)=='1'){//为负
Shang.append('0');
}else{//非负
Yu=new StringBuilder(tmp);
Shang.append('1');
}
}
//4.结果
String YuStr= Yu.toString();
String ShangStr= Shang.toString();
//被除数和余数同号
if(!srcNeg&&destNeg){//除数正,被除数负
YuStr=negation(YuStr);
ShangStr=negation(ShangStr);
} else if (srcNeg&&!destNeg) {//除数负,被除数正
ShangStr=negation(YuStr);
}else if(srcNeg&&destNeg){//都是负
YuStr=negation(YuStr);
}

remainderReg=new DataType(YuStr);
return new DataType(ShangStr);
}

//左移
public StringBuilder leftshift(String beforeStr){
StringBuilder afterStr = new StringBuilder();
for(int i=1;i<32;i++){//跳过第一位
afterStr.append(beforeStr.charAt(i));
}
return afterStr;
}

If you like my blog, you can approve me by scanning the QR code below.

Other Articles
Article table of contents TOP
  1. 1. 一. 计算两个32位二进制整数补码真值的和
    1. 1.1. 1. 步骤
    2. 1.2. 2. 【注意】结果反转
    3. 1.3. 3. 完整代码
    4. 1.4. 4. 更简单:
  2. 2. 二、计算两个32位二进制整数补码真值的差
    1. 2.1. 1. 取反操作
    2. 2.2. 2.完整代码
  3. 3. 三、两个二进制整数的乘积(布斯乘法,结果低位截取后32位)
    1. 3.1. 1.布斯乘法
    2. 3.2. 2. 算术右移方法:
    3. 3.3. 完整代码
  4. 4. 四、两个二进制整数的除法
    1. 4.1. 1. 恢复余数除法
    2. 4.2. 2. 不恢复余数除法
    3. 4.3. 3. 调整余数和商的符号
    4. 4.4. 完整代码
Please enter keywords to search