#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//计算机组成原理作业:浮点数的加减法
//************ 二进制整数 ************
//由真值求补码(二进制整数)
void trueInt_to_twocomplement(char* bin);
//由补码求真值(二进制整数)
void twocomplementInt_to_trueInt(char* bin);
//二进制转十进制(双符号位二进制整数)
int binary_to_decimal(char* bin);
//双符号位二进制整数的加法
void add_Intbin(char* bin1, char* bin2, char* bin);
//************ 二进制小数 ************
//由真值求补码(二进制小数)
void trueDouble_to_twocomplement(char* bin);
//由补码求真值(二进制小数)
void twocomplementDouble_to_trueDouble(char* bin);
//双符号位二进制小数的加法
void add_Doublebin(char* bin1, char* bin2, char* bin);
//************ 其他 ************
//向右规格化,小数点向左移
void right_standardize(char* bin);
//向左规格化,小数点向右移, *n 用来记录小数点移动了多少位
void left_standardize(char* bin, int* n);
//对阶
void equal_exponent(char* bin, int n);
//比较两浮点数阶码,即比较 Ex 和 Ey
int compare_twocomplementInt(char* Ex_bin, char* Ey_bin);
//尾数相加
void mantissa_addition(char* Mx_bin, char* My_bin, char* bin, char* E);
//规格化数,X = Mx * 2^(Ex), Y = My * 2^(Ey)
typedef struct floatNumber
{
char M[99];
char E[99];
}floatNumber, *pfloatNumber;
int main() {
//开辟内存,并给规格化数赋初值
pfloatNumber x = (pfloatNumber)malloc(sizeof(floatNumber));
if(x == NULL) {
printf("分配内存失败\n");
exit(-1);
}
printf("Please Enter A Value For Mx:");
scanf("%s", &(x->M));
printf("Please Enter A Value For Ex:");
scanf("%s", &(x->E));
pfloatNumber y = (pfloatNumber)malloc(sizeof(floatNumber));
if(y == NULL) {
printf("分配内存失败\n");
exit(-1);
}
printf("Please Enter A Value For My:");
scanf("%s", &(y->M));
printf("Please Enter A Value For Ey:");
scanf("%s", &(y->E));
printf("\n---------------------------\n");
printf("当前的规格化数 x 为:%s * 2^%s\n", x->M, x->E);
printf("\n---------------------------\n");
printf("当前的规格化数 y 为:%s * 2^%s\n", y->M, y->E);
//求出 Mx,Ex,My,Ey 的补码
trueDouble_to_twocomplement(x->M);
trueInt_to_twocomplement(x->E);
trueDouble_to_twocomplement(y->M);
trueInt_to_twocomplement(y->E);
printf("\n---------------------------\n");
printf("twocomplement_Mx = %s\n", x->M);
printf("\n---------------------------\n");
printf("twocomplement_Ex = %s\n", x->E);
printf("\n---------------------------\n");
printf("twocomplement_My = %s\n", y->M);
printf("\n---------------------------\n");
printf("twocomplement_Ey = %s\n", y->E);
//求阶差
int sub_E = compare_twocomplementInt(x->E, y->E);
printf("\n---------------------------\n");
printf("sub_E = %d\n", sub_E);
//保留大阶
char E[99];
sub_E < 0 ? strcpy(E, y->E) : strcpy(E, x->E);
printf("\n---------------------------\n");
printf("E = %s\n", E);
//对阶
char twocomplement[99];
sub_E <= 0 ? equal_exponent(x->M, abs(sub_E)) : equal_exponent(y->M, abs(sub_E));
sub_E <= 0 ? strcpy(twocomplement, x->M) : strcpy(twocomplement, y->M);
printf("\n---------------------------\n");
printf("twocomplement = %s\n", twocomplement);
//尾数相加
char bin[99];
mantissa_addition(x->M, y->M, bin, E);
printf("\n---------------------------\n");
printf("bin = %s\n", bin);
printf("\n---------------------------\n");
printf("E = %s\n", E);
twocomplementInt_to_trueInt(E);
twocomplementDouble_to_trueDouble(bin);
printf("\n---------------------------\n");
printf("当前的规格化数 x + y 为:%s * 2^%s\n", bin, E);
//释放内存
free(x);
free(y);
return 0;
}
//由真值求补码(二进制整数)
void trueInt_to_twocomplement(char* bin) {
char newBin[99];
//原码
char newBin1[99];
//反码
char newBin2[99];
//补码
char newBin3[99];
//正数的原反补相同
if (bin[0] != '-') {
newBin[0] = newBin[1] = '0';
int i;
for (i = 0; i < strlen(bin); i++) {
newBin[i + 2] = bin[i];
}
newBin[i + 2] = '\0';
strcpy(bin, newBin);
}//负数
else {
//原码
newBin1[0] = newBin1[1] = '1';
int i;
for (i = 1; i < strlen(bin); i++) {
newBin1[i + 1] = bin[i];
}
newBin1[i + 1] = '\0';
newBin2[0] = newBin2[1] = '1';
for (i = 2; i < strlen(newBin1); i++) {
newBin2[i] = newBin1[i] == '0' ? '1' : '0';
}
newBin2[i] = '\0';
for (int i = 0; i < strlen(newBin2); i++) {
newBin3[i] = newBin2[i];
}
newBin3[strlen(newBin2)] = '\0';
//bool 用于判断有没有进行进位操作
//0 表示未进位,1 表示进位操作已完成,退出循环
int bool = 0;
for (int i = strlen(newBin2) - 1; i >= 2 && bool == 0; i--) {
//如果当前位为 0 的话,直接进位就行,并把 bool 改成 1,完成进位操作,退出循环
if (newBin2[i] == '0') {
newBin3[i] = '1';
bool = 1;
}//如果当前为为 1 的话,当前位变为 0,向下一位进 1,继续循环
else {
newBin3[i] = '0';
}
}
//反码是 111 这种情况,说明真值为 0,0 的补码是 0
if (bool == 0) {
return "0";
}
else {
strcpy(bin, newBin3);
}
}
}
//由真值求补码(二进制小数)
void trueDouble_to_twocomplement(char* bin) {
char newBin[99];
//原码
char newBin1[99];
//反码
char newBin2[99];
//补码
char newBin3[99];
//正数的原反补相同
if (bin[0] != '-') {
newBin[0] = newBin[1] = '0';
int i;
for (i = 1; i < strlen(bin); i++) {
newBin[i + 1] = bin[i];
}
newBin[i + 1] = '\0';
strcpy(bin, newBin);
}//负数
else {
//原码
newBin1[0] = newBin1[1] = '1';
int i;
for (i = 2; i < strlen(bin); i++) {
newBin1[i] = bin[i];
}
newBin1[i] = '\0';
newBin2[0] = newBin2[1] = '1';
newBin2[2] = '.';
for (i = 3; i < strlen(newBin1); i++) {
newBin2[i] = newBin1[i] == '0' ? '1' : '0';
}
newBin2[i] = '\0';
for (int i = 0; i < strlen(newBin2); i++) {
newBin3[i] = newBin2[i];
}
newBin3[strlen(newBin2)] = '\0';
//bool 用于判断有没有进行进位操作
//0 表示未进位,1 表示进位操作已完成,退出循环
int bool = 0;
for (int i = strlen(newBin2) - 1; i >= 3 && bool == 0; i--) {
//如果当前位为 0 的话,直接进位就行,并把 bool 改成 1,完成进位操作,退出循环
if (newBin2[i] == '0') {
newBin3[i] = '1';
bool = 1;
}//如果当前为为 1 的话,当前位变为 0,向下一位进 1,继续循环
else {
newBin3[i] = '0';
}
}
//真值为 0,0 的补码是 0
if (bool == 0) {
return "0";
}
else {
strcpy(bin, newBin3);
}
}
}
//由补码求真值(二进制整数)
void twocomplementInt_to_trueInt(char* bin) {
//newBin 字符数组用来存放真值
char newBin[99];
char newBin1[99];
char newBin2[99];
//补码为 0
if (strlen(bin) == 1 && bin[0] == '0') {
return "0";
}
//正数的原反补相同
if(bin[0] == '0' && bin[1] == '0') {
int i;
for (i = 2; i < strlen(bin); i++) {
newBin[i - 2] = bin[i];
}
newBin[i - 2] = '\0';
}
else {
newBin[0] = '-';
//先直接去除符号位(暂时不考虑符号位后面的变化)
int i;
for (i = 2; i < strlen(bin); i++) {
newBin1[i - 2] = bin[i];
}
newBin1[i - 2] = '\0';
//可以判断有没有遇到 1,遇到 1 的话直接退出循环
int bool = 0;
for (i = strlen(newBin1) - 1; i >= 0 && bool == 0; i--) {
if (newBin1[i] == '1') {
newBin2[i] = '0';
bool = 1;
}
else {
newBin2[i] = '1';
}
}
//中途碰到 1
if (bool == 1) {
for (int j = 0; j <= i; j++) {
newBin2[j] = newBin1[j];
}
}
newBin2[strlen(newBin1)] = '\0';
//按位取反就是真值
for (i = 0; i < strlen(newBin2); i++) {
newBin[i + 1] = newBin2[i] == '0' ? '1' : '0';
}
newBin[i + 1] = '\0';
}
strcpy(bin, newBin);
}
//由补码求真值(二进制小数)
void twocomplementDouble_to_trueDouble(char* bin) {
//newBin 字符数组用来存放真值
char newBin[99];
char newBin1[99];
char newBin2[99];
//补码为 0
if (strlen(bin) == 1 && bin[0] == '0') {
return "0";
}
//正数的原反补相同
if (bin[0] == '0' && bin[1] == '0') {
int i;
for (i = 1; i < strlen(bin); i++) {
newBin[i - 1] = bin[i];
}
newBin[i - 1] = '\0';
}
else {
newBin[0] = '-';
newBin[1] = '0';
newBin[2] = '.';
//先直接去除符号位(暂时不考虑符号位后面的变化)
int i;
for (i = 3; i < strlen(bin); i++) {
newBin1[i - 3] = bin[i];
}
newBin1[i - 3] = '\0';
//可以判断有没有遇到 1,遇到 1 的话直接退出循环
int bool = 0;
for (i = strlen(newBin1) - 1; i >= 0 && bool == 0; i--) {
if (newBin1[i] == '1') {
newBin2[i] = '0';
bool = 1;
}
else {
newBin2[i] = '1';
}
}
//中途碰到 1
if (bool == 1) {
for (int j = 0; j <= i; j++) {
newBin2[j] = newBin1[j];
}
}
newBin2[strlen(newBin1)] = '\0';
//按位取反就是真值
for (i = 0; i < strlen(newBin2); i++) {
newBin[i + 3] = newBin2[i] == '0' ? '1' : '0';
}
newBin[i + 3] = '\0';
}
strcpy(bin, newBin);
}
//二进制转十进制(双符号位二进制整数)
int binary_to_decimal(char* bin) {
int res;
res = 0;
int exponent = strlen(bin) - 3;
for (int i = 2; i < strlen(bin); i++, exponent--) {
res = bin[i] == '0' ? res : res + pow(2, exponent);
}
return bin[0] == '0' ? res : 0 - res;
}
//比较两浮点数阶码,即比较 Ex 和 Ey
int compare_twocomplementInt(char* Ex_bin, char* Ey_bin) {
int decimal_Ex = binary_to_decimal(Ex_bin);
int decimal_Ey = binary_to_decimal(Ey_bin);
return decimal_Ex - decimal_Ey;
}
//双符号位二进制整数的加法
void add_Intbin(char* bin1, char* bin2, char* bin) {
char newBin1[99];
char newBin2[99];
char newBin3[99];
int length = max(strlen(bin1), strlen(bin2));
//使位数与位数大的保持一致(即位数小的前面补 0,便于后面加法运算)
int i,j;
for (i = 0; i < length; i++) {
newBin1[i] = bin1[i] == '1' ? '1' : '0';
newBin2[i] = bin2[i] == '1' ? '1' : '0';
}
newBin1[length] = newBin2[length] = '\0';
if (length == strlen(bin1)) {
for (i = 2; i < 2 + strlen(bin1) - strlen(bin2); i++) {
newBin2[i] = newBin2[0] == '0' ? '0' : '1';
}
for (i = strlen(bin2), j = 2; i < strlen(bin1); i++,j++) {
newBin2[i] = bin2[j];
}
}
else if (length == strlen(bin2)) {
for (i = 2; i < 2 + strlen(bin2) - strlen(bin1); i++) {
newBin1[i] = newBin1[i] == '0 ' ? '0' : '1';
}
for (j = 2; i < strlen(bin2); i++, j++) {
newBin1[i] = bin1[j];
}
}
printf("newBin1 = %s\n", newBin1);
printf("newBin2 = %s\n", newBin2);
// bool 的值为 0,表示没有进位, bool 的值为 1,表示有进位
int bool = 0;
for (i = strlen(newBin1) - 1; i >= 0; i--) {
if (newBin1[i] == '0' && newBin2[i] == '0') {
newBin3[i] = bool == 0 ? '0' : '1';
bool = 0;
}
else if ((newBin1[i] == '0' && newBin2[i] == '1') || (newBin1[i] == '1' && newBin2[i] == '0')) {
newBin3[i] = bool == 0 ? '1' : '0';
}
else if (newBin1[i] == '1' && newBin2[i] == '1') {
newBin3[i] = bool == 0 ? '0' : '1';
bool = 1;
}
}
newBin3[strlen(newBin1)] = '\0';
printf("newBin3 = %s\n", newBin3);
strcpy(bin, newBin3);
}
//双符号位二进制小数的加法
void add_Doublebin(char* bin1, char* bin2, char* bin) {
char newBin1[99];
char newBin2[99];
char newBin3[99];
char newBin4[99];
int length = max(strlen(bin1), strlen(bin2));
int i;
//去掉小数点,并且使位数与位数大的保持一致(即位数小的后面补 0,便于后面加法运算)
for (i = 0; i < 2; i++) {
newBin1[i] = bin1[i];
newBin2[i] = bin2[i];
}
for (i = 3; i < length; i++) {
newBin1[i - 1] = bin1[i] == '1' ? '1' : '0';
newBin2[i - 1] = bin2[i] == '1' ? '1' : '0';
}
newBin1[i - 1] = newBin2[i - 1] = '\0';
// bool 的值为 0,表示没有进位, bool 的值为 1,表示有进位
int bool = 0;
for (i = strlen(newBin1) - 1; i >= 0; i--) {
if (newBin1[i] == '0' && newBin2[i] == '0') {
newBin3[i] = bool == 0 ? '0' : '1';
bool = 0;
}
else if ((newBin1[i] == '0' && newBin2[i] == '1') || (newBin1[i] == '1' && newBin2[i] == '0')) {
newBin3[i] = bool == 0 ? '1' : '0';
}
else if (newBin1[i] == '1' && newBin2[i] == '1') {
newBin3[i] = bool == 0 ? '0' : '1';
bool = 1;
}
}
newBin3[strlen(newBin1)] = '\0';
for (i = 0; i < 2; i++) {
newBin4[i] = newBin3[i];
}
newBin4[2] = '.';
for (i = 2; i < strlen(newBin3); i++) {
newBin4[i + 1] = newBin3[i];
}
newBin4[i + 1] = '\0';
strcpy(bin, newBin4);
}
//尾数相加
void mantissa_addition(char* Mx_bin, char* My_bin, char* bin, char* E) {
add_Doublebin(Mx_bin, My_bin, bin);
//规格化:
// 采用双符号位的补码: S = 00.1xxx xxxx...
// S = 11.0xxx xxxx...
//若不是规格化的数,需要尾数向左移动,以实现规格化,即向左规格化
//如果尾数相加发生正溢或负溢,即S = 01.xxxx xxxx...或S = 10.xxxx xxxx...,向右规格化
if ((bin[0] == '0' && bin[1] == '1') || (bin[0] == '1' && bin[1] == '0')) {
right_standardize(bin);
char newBin[99];
add_Intbin(E, "001", newBin);
strcpy(E, newBin);
}
else {
char newBin[99];
char newBin1[99];
newBin1[0] = '-';
int n;
left_standardize(bin, &n);
printf("n = %d\n", n);
itoa(n, newBin, 2);
printf("newBin = %s\n", newBin);
int i;
for (i = 0; i < strlen(newBin); i++) {
newBin1[i + 1] = newBin[i];
}
newBin1[i + 1] = '\0';
printf("newBin1 = %s\n", newBin1);
trueInt_to_twocomplement(newBin1);
printf("newBin1 = %s\n", newBin1);
add_Intbin(E, newBin1, newBin);
strcpy(E, newBin);
}
}
//对阶
void equal_exponent(char* bin, int n) {
char newBin[99];
int i;
for (i = 0; i < 3; i++) {
newBin[i] = bin[i];
}
for (i = 3; i < n + 3; i++) {
newBin[i] = '0';
}
for (i = 3; i < strlen(bin); i++) {
newBin[i + n] = bin[i];
}
newBin[i] = '\0';
strcpy(bin, newBin);
}
//向右规格化,小数点向左移
void right_standardize(char* bin) {
char newBin[99];
newBin[0] = newBin[1] = bin[0];
newBin[2] = '.';
newBin[3] = bin[1];
int i;
for (i = 3; i < strlen(bin); i++) {
newBin[i + 1] = bin[i];
}
newBin[i] = '\0';
strcpy(bin, newBin);
}
//向左规格化,小数点向右移, *n 用来记录小数点移动了多少位
void left_standardize(char* bin, int* n) {
static char newBin[99];
memset(newBin, '\0', sizeof(newBin));
char newBin1[99];
//去掉小数点
newBin1[0] = newBin1[1] = bin[0];
for (int i = 3; i < strlen(bin); i++) {
newBin1[i - 1] = bin[i];
}
newBin1[strlen(bin) - 1] = '\0';
int index = 0;
//如果符号位是 11,寻找第一个 0,如果符号位是 00,寻找第一个 1
char c = bin[0] == '0' ? '1' : '0';
for (int i = 0; i < strlen(newBin1); i++) {
//找到目标,index 记录对应的索引位置,结束for循环
if (newBin1[i] == c) {
index = i;
break;
}
}
newBin[0] = newBin1[index - 2];
printf("newBin[0] = %c\n", newBin[0]);
newBin[1] = newBin1[index - 1];
newBin[2] = '.';
int i, j;
for (i = index, j = 3; i < strlen(newBin1); i++,j++) {
newBin[j] = newBin1[i];
}
newBin[j] = '\0';
*n = index - 2;
strcpy(bin, newBin);
}