1. 实验要求
在Transformer类中实现以下6个方法
- 将整数真值(十进制表示)转化成补码表示的二进制,默认长度32位
public String intToBinary(String numStr)
- 将补码表示的二进制转化成整数真值(十进制表示)
public String binaryToInt(String binStr)
- 将十进制整数的真值转化成NBCD表示(符号位用4位表示)
public String decimalToNBCD(String decimal)
- 将NBCD表示(符号位用4位表示)转化成十进制整数的真值
public String NBCDToDecimal(String NBCDStr)
-
将浮点数真值转化成32位单精度浮点数表示
-
负数以"-"开头,正数不需要正号
-
考虑正负无穷的溢出(“+Inf”, “-Inf”,见测试用例格式)
-
public String floatToBinary(String floatStr)
- 将32位单精度浮点数表示转化成浮点数真值
- 特殊情况同上
public String binaryToFloat(String binStr)
2. 实验攻略
本次实验推荐使用的库函数有
Integer.parseInt(String s)
Float.parseFloat(String s)
String.valueOf(int i)
String.valueOf(float f)
本次实验不允许使用的库函数有
Integer.toBinaryString(int i)
Float.floatToIntBits(float value)
Float.intBitsToFloat(int bits)
3.具体实现
3.1 整数转二进制补码
- 判断正负,如果为正数,则补码以
0
开始,如果为负数,则补码以1
开始 - 常规思路:统一转化为正数,转换为补码,再根据正负,判断是否需要进行取反加1的操作。
- 其他思路:可以利用模系统互相等价的原理
例如:如果我要求-3的补码,我先求 -3 + 8 = 5 的补码,最后改变符号位即可。因此,代码如下
3.1.1代码实现
public static String intToBinary(String numStr) {
int value = Integer.parseInt(numStr);
char[] ans = new char[32];
Arrays.fill(ans,'0');
bool isNeg = false;
if(value < 0){
value += Math.pow(2, 31);
isNeg = true;
}
int index = 31;
while (value > 0){
if(value % 2 == 1){
ans[index] = '1';
}
index--;
value /= 2;
}
if(isNeg)
{
ans[0] = '1' ;
}
return new String(ans);
}
3.1.2 测试用例
@Test
public void intToBinaryTest1() {
assertEquals("00000000000000000000000000000010", Transformer.intToBinary("2"));
}
@Test
public void intToBinaryTest2() {
assertEquals("10000000000000000000000000000000", Transformer.intToBinary("-2147483648"));
}
@Test
public void intToBinaryTest3() {
assertEquals("00000000000000000000000000001001", Transformer.intToBinary("9"));
}
@Test
public void intToBinaryTest4() {
assertEquals("00000000000000000000000000101001", Transformer.intToBinary("41"));
}
@Test
public void intToBinaryTest5() {
assertEquals("11111111111111111111111111111111", Transformer.intToBinary("-1"));
}
3.2 二进制补码转整数
二进制转补码,也可以利用模系统互相等价的原理。
可以从
−
3
=
1101
-3 = 1101
−3=1101
3
=
0011
3 = 0011
3=0011找到规律
3.2.1 代码实现
public static String binaryToInt(String binStr) {
char[] num = binStr.toCharArray();
int ans = 0;
// 计算从第1位到第31位的数字
for(int i = 1; i < 32; i++){
ans += (num[i] - '0') * Math.pow(2, 31 - i);
}
// 计算第0位的数字并减去,
ans -= (num[0] - '0') * Math.pow(2, 31);
return String.valueOf(ans);
}
3.2.2 测试用例
@Test
public void binaryToIntTest1() {
assertEquals("2", Transformer.binaryToInt("00000000000000000000000000000010"));
}
@Test
public void binaryToIntTest2() {
assertEquals("1", Transformer.binaryToInt("00000000000000000000000000000001"));
}
@Test
public void binaryToIntTest3() {
assertEquals("2147483647", Transformer.binaryToInt("01111111111111111111111111111111"));
}
@Test
public void binaryToIntTest4() {
assertEquals("-1", Transformer.binaryToInt("11111111111111111111111111111111"));
}
3.3 十进制数转NBCD码
规则:
- NBCD码的符号位是
1100
代表正数,1101
代表负数 - 默认得到的NBCD码是32位,因此可以开一个28位的
char[28]
,并将里面填满0
- 首先将十进制数进行独立,也就是说通过循环取得每一位的数字,再对每一个数字
digit
进行处理,转化为2进制即可
因此,代码如下
3.3.1 代码实现
//将十进制整数的真值转化成NBCD表示(符号位用4位表示)
public static String decimalToNBCD(String decimalStr) {
int num = Integer.parseInt(decimalStr);
boolean isPositive = num >= 0; // 判断是正数还是负数
num = Math.abs(num);
char[] ans = new char[28];
// 额外用count代表下表,方便从右往左进行处理
int count = 27;
Arrays.fill(ans, '0');
while (num != 0) {
int digit = num % 10; //通过循环取得每一个具体的数字
int time = 0; //额外开一个循环,循环4次,用time记录循环次数
while (time < 4) {
ans[count] = (char) (digit % 2 + '0');
count--;
digit /= 2;
time++;
}
num /= 10;
}
if (isPositive) {
return "1100" + new String(ans);
} else {
return "1101" + new String(ans);
}
}
3.3.2 测试用例
@Test
public void decimalToNBCDTest1() {
assertEquals("11000000000000000000000000010000", Transformer.decimalToNBCD("10"));
}
@Test
public void decimalToNBCDTest2() {
assertEquals("11000000000010010000100100011001", Transformer.decimalToNBCD("90919"));
}
@Test
public void decimalToNBCDTest3() {
assertEquals("11000000000100000000000000001001", Transformer.decimalToNBCD("100009"));
}
3.4 NBCD码转十进制数
- 确定正负号,判断字符串NBCD码以
1100
开头还是以1101
开头 - 对NBCD码每四位进行一次处理,通过二进制转化为十进制数的方式,得到每一位
digit
数字。 - 得到每4个NBCD码代表的一位数字后,需要将其转化为十进制数,乘以10或者100……
代码如下
3.4.1 代码实现
//将NBCD表示(符号位用4位表示)转化成十进制整数的真值
public static String NBCDToDecimal(String NBCDStr) {
int ans = 0;
int tenTime = 0;
boolean isPositive = NBCDStr.startsWith("1100");
/**
* 此处额外进行了i--,所以就不需要在循环中再进行-操作了
*/
for (int i = NBCDStr.length() - 1; i >= 4; ) {
int time = 0;
int tmp = 0;
while (time < 4 && i >= 4) {
tmp += Math.pow(2, time) * (NBCDStr.charAt(i) - '0');
time++;
i--;
}
ans += Math.pow(10, tenTime) * tmp;
tenTime++;
}
/**
* 小心-0 和 +0. 在NBCD码中需要进行区分
*/
return isPositive ? String.valueOf(ans) : "-" + ans;
}
3.4.2 测试用例
@Test
public void NBCDToDecimalTest1() {
assertEquals("10", Transformer.NBCDToDecimal("11000000000000000000000000010000"));
}
@Test
public void NBCDToDecimalTest2() {
assertEquals("90919", Transformer.NBCDToDecimal("11000000000010010000100100011001"));
}
@Test
public void NBCDToDecimalTest3() {
assertEquals("-90919", Transformer.NBCDToDecimal("11010000000010010000100100011001"));
}
@Test
public void NBCDToDecimalTest4() {
assertEquals("100509", Transformer.NBCDToDecimal("11000000000100000000010100001001"));
}
@Test
public void NBCDToDecimalTest5() {
assertEquals("-9", Transformer.NBCDToDecimal("11010000000000000000000000001001"));
}
@Test
public void NBCDToDecimalTest6() {
assertEquals("9000019", Transformer.NBCDToDecimal("11001001000000000000000000011001"));
}
@Test
public void NBCDToDecimalTest7() {
assertEquals("-9000009", Transformer.NBCDToDecimal("11011001000000000000000000001001"));
}
@Test
public void NBCDToDecimalTest8() {
assertEquals("-0", Transformer.NBCDToDecimal("11010000000000000000000000000000"));
}
3.5 浮点数转二进制数
3.6 二进制数转浮点数
- 熟悉规格化数的相关表示方式,处理好
NaN
+Inf
-Inf
、非规格化数的特殊情况 - 处理二进制数的字符串,将其切割为三部分:符号部分、指数部分、尾数部分
- 通过符号部分,判断正负号
- 通过指数部分,进行情况分析
- 如果指数部分为
11111111
,且尾数部分全为0 ,则代表的是无穷 - 如果指数部分为
11111111
,且尾数部分不全为0,则代表的是NaN
- 如果指数部分为
00000000
,且尾数部分全为0,则代表的是+0
或-0
- 如果指数部分为
0000000
,且尾数部分不全为0,则代表的是非规格化数,阶值默认为-126
- 当阶码的值为1-254时,则进行e-127的操作,因为阶码是移码的格式,所以阶值 = 阶码真值 - 偏置常数
- 对尾数部分进行处理,将其转化为二进制数,但需要注意是小数点后的二进制,因此,是乘以 2 − i 2^{-i} 2−i
- 最后,进行计算。
- 如果是规格化数,则 v a l u e = 1. f ∗ 2 e x p value = 1.f*2^{exp} value=1.f∗2exp
- 如果是非规格化数,则 v a l u e = 0. f ∗ 2 − 126 value = 0.f*2^{-126} value=0.f∗2−126
- 最后,需要小心
Math.pow
返回的是double,而我们需要的是float ,因此需要强制类型转换
代码如下
3.6.1 代码实现
public static String binaryToFloat(String binStr) {
// 判断正负
boolean isPos = binStr.charAt(0) == '0';
String expStr = binStr.substring(1, 9);
String tailStr = binStr.substring(9);
float tailNum = 0;
// 处理指数部分
int expNum = Integer.parseInt(expStr, 2) - 127;
int tailCount = -1;
float ans;
// 处理尾数部分
for (int i = 0; i < tailStr.length(); i++) {
tailNum += Math.pow(2, tailCount) * (tailStr.charAt(i) - '0');
tailCount--;
}
if (expStr.equals("11111111")) {
if (!tailStr.contains("1")) {
return isPos ? "+Inf" : "-Inf";
} else {
return "NaN";
}
} else if (expStr.equals("00000000")) {
// 非规格化数,e = -126
ans = (float) (Math.pow(2, expNum + 1) * tailNum);
} else {
// 规格化数,尾数 = 1.xxxxxx
tailNum += 1;
ans = (float) (Math.pow(2, expNum) * tailNum);
}
return isPos ? String.valueOf(ans) : "-" + ans;
}
3.6.2 测试用例
@Test
public void binaryToFloatTest1() {
assertEquals(String.valueOf((float) Math.pow(2, -127)), Transformer.binaryToFloat("00000000010000000000000000000000"));
}
@Test
public void binaryToFloatTest2() {
assertEquals(String.valueOf((float) Math.pow(2, 127)), Transformer.binaryToFloat("01111111000000000000000000000000"));
}
@Test
public void binaryToFloatTest3() {
assertEquals(String.valueOf(1044.32), Transformer.binaryToFloat("01000100100000101000101000111101"));
}
@Test
public void binaryToFloatTest4() {
assertEquals(String.valueOf(1.32), Transformer.binaryToFloat("00111111101010001111010111000011"));
}
@Test
public void binaryToFloatTest5() {
assertEquals(String.valueOf(-0.5), Transformer.binaryToFloat("10111111000000000000000000000000"));
}
@Test
public void binaryToFloatTest6() {
assertEquals(String.valueOf(-(float) Math.pow(2, -128)), Transformer.binaryToFloat("10000000001000000000000000000000"));
}
@Test
public void binaryToFloatTest7() {
assertEquals(String.valueOf(-(float) Math.pow(2, -126)), Transformer.binaryToFloat("10000000100000000000000000000000"));
}
@Test
public void binaryToFloatTest8() {
assertEquals(String.valueOf(-(float) 0), Transformer.binaryToFloat("10000000000000000000000000000000"));
}
@Test
public void binaryToFloatTest9() {
assertEquals(String.valueOf( (float) 0), Transformer.binaryToFloat("00000000000000000000000000000000"));
}