目前共有6篇帖子。 内容转换:不转换▼
 
点击 回复
318 5
【程序】原码一位乘法
一派护法 十九级
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指定(或者省略不写)

回复帖子

内容:
用户名: 您目前是匿名发表
验证码:
(快捷键:Ctrl+Enter)
 

本帖信息

点击数:318 回复数:5
评论数: ?
作者:巨大八爪鱼
最后回复:巨大八爪鱼
最后回复时间:2016-12-1 13:12
 
©2010-2024 Arslanbar Ver2.0
除非另有声明,本站采用知识共享署名-相同方式共享 3.0 Unported许可协议进行许可。