目前共有6篇帖子。
【程序】原碼一位乘法
1樓 巨大八爪鱼 2016-12-1 12:21
#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;
}
/*************************************/

2樓 巨大八爪鱼 2016-12-1 12:23
【運行結果】
請輸入兩個數: 6 -11
計算結果: -66
3樓 巨大八爪鱼 2016-12-1 12:53
在運算過程中,A、B暫存器都被看作8位的無符號數。
當然也可以被看作是有雙符號位,且運算過程中第一符號位(第八位)恆為0,第二符號位(第七位)用來保存進位。雖然雙符號位+7位有效數值位一共9位,但由於最高位(第八位)恆為0,所以直接用八位的unsigned char保存就行了。
4樓 巨大八爪鱼 2016-12-1 12:58
儘管第一符號位始終為0可以略去,但由於在設計硬體電路時常將乘法器和除法器合成為一個乘除部件,且除法運算需要雙符號位,所以在實際的硬體電路中一般不省略第一符號位。
5樓 巨大八爪鱼 2016-12-1 13:05
例如,若A和B都等於127,那麼執行A+=B後,A的值為254,對應的二進制數為11111110。這裡就產生了溢出,因為最高位(第七位)為1。
如果添上省略掉的第一符號位,就是011111110。可見雙符號位為01,為正溢。
然後執行右移操作,同時把最低位的0保存到C暫存器的最高位上,於是A就變成了01111111,添上第一符號位後是001111111,這樣溢出位就被移回了數值位部分。
6樓 巨大八爪鱼 2016-12-1 13:12
邏輯移位與算術移位的區別
邏輯移位:空位始終補0,在C語言中用unsigned指定
算術移位:負數右移時空位補1,其他和邏輯移位一樣,在C語言中用signed指定(或者省略不寫)

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。