#include <stdio.h>
#pragma warning(disable:4996) // 消除scanf警告
// 原碼一位乘法函數
// 返回值為16位原碼錶示的積
short multiply(char x, char y)
{
char i;
char rs[2];
unsigned char a = 0; // 存放部分積累加和, 初始值為0
unsigned char b = x & 0x7f; // 存放不帶符號位的x
unsigned char c = y & 0x7f; // 存放不帶符號位的y
for (i = 0; i < 7; i++) // 8位有符號數一共有7位數值位
{
if (c & 1)
a += b;
c >>= 1;
// 將A的末位移入C的高位
// 注意unsigned char的移位是邏輯移位, char是算術移位
if (a & 1)
c |= 0x80;
a >>= 1;
}
// 兩個7位的數相乘, 積為14位, 加上符號位就是15位
// 而short有16位, 所以次高位一定為0
rs[0] = c; // c的高7位為低位部分
rs[1] = a; // a為高位部分
*(unsigned short *)rs >>= 1; // 右移空出次高位, unsigned表示邏輯移位(即空位一定添0)
// 次高位(第14位)恆為0
// 異號得負
if (((x ^ y) & 0x80) != 0)
rs[1] |= 0x80;
return *(short *)rs;
}
/*********** 以下為測試代碼 ***********/
// 32位補碼轉8位原碼
char convert(int n)
{
char c = (char)(n & 0xff);
if (c < 0)
{
c--;
c ^= 0x7f; // 低7位反轉
}
return c;
}
// 16位原碼轉32位補碼
int restore(short s)
{
int n = s & 0x7fff;
if (s & 0x8000)
n = ~n + 1;
return n;
}
int main(void)
{
int n; // 輸入的整數個數
int xd, yd; // 以補碼錶示的兩個32位的乘數
short result; // 16位計算結果(原碼錶示)
printf("請輸入兩個數: ");
n = scanf("%d%d", &xd, &yd);
if (n != 2)
{
puts("數字格式不正確!");
return 0;
}
else if (xd < -127 || xd > 127 || yd < -127 || yd > 127)
{
// 注: 雖然char能夠保存-128, 但是這個數無法用8位的原碼錶示
puts("這是一個8位的原碼乘法器,所以輸入的數必須在-127~127之間!");
return 0;
}
result = multiply(convert(xd), convert(yd)); // 計算
printf("計算結果: %d\n", restore(result));
return 0;
}
/*************************************/