有符号数的加减乘除

本文深入探讨了有符号数与无符号数在计算机中的表示方式,特别是通过补码表示负数的方法,以及如何通过无符号乘法运算处理有符号数的乘法,避免溢出问题。文章还提供了计算补码的具体步骤和实例,以及在编程中如何通过简单的加法操作实现补码转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先用4位来解释,32位太长,不好解释,四位有符号数的范围是-8~7,无符号数是0~15.
1. 让我们设想一下有符号数的-2 * -2,-2的补码是1110,在无符号数里是14,所以无符号数的乘法相当于14 * 14
二进制乘法
1110
*1110
-------
0000
1110
1110

1110

11000100
4位表示就是0100,补码表示是4,二进制也是4
而有符号-2 * -2 = 4,没有问题, 无符号14 * 14 = 11000100(二进制,这里溢出了),4位截取高位=0100=4

  1. 让我们设想一下有符号数的-2 * 2,-2的补码是1110,2的补码是0010,在无符号数里是14,所以无符号数的乘法相当于14 * 2
    1110
    *0010
    -------
    11100 
    截取最高位,就是1100,就是-4,而14 * 2溢出,得到的也是1100,就是十进制12.

首先,我们从书上了解到关键的几个知识点:
1. 对无符号和补码乘法,乘法运算的位级表示都是一样的。
2. 机器使用一种乘法指令来进行有符号和无符号整数的乘法,也就是都采用无符号乘法处理,再取低位

 

按照【谭浩强.C程序设计(第三版).北京:清华大学出版社,2005】的第40页至第41页所述,求一个负数的补码的方法如下:

【例】求-10的补码的方法如下:

1)取-10的绝对值10;

2)10的绝对值的二进制形式为1010;

3)对1010取反得1111 1111 1111 0101(这里假定一个整数占16位)

4)再加1得1111 1111 1111 0110;

即取补码的步骤是将其绝对值按位取反再加1即可……

 

仍基于上例进行分析,16位存储空间能够存储的有符号型数的范围为-2^16~2^16-1,-10的补码按无符号类型计算其值为65526。

编程时可用如下语句实现:

int i=-10;

i=~abs(i)+1;//abs为取绝对值,~为按位取反

这个语句涉及到了三个操作:一是求绝对值,二是按位取反,三是加1

 

其实可以用一个加法操作即可搞定……

int i=-10;

i=i+2^16;

可以验证,这种方法是等价的,-10+2^16=65526,在一个有符号型存储变量中存储这个数,相当于存储了一个负数……

 

其通用的方法是:

变量A用N位来存储,当其为负数时计算其补码的方法是A=A+2^N;

 

这种方法适用于以下情况但不局限于以下情况:

例如用matlab产生了一组有符号型数数据,产生这组数据的目的是传给FPGA进行处理,当FPGA的IP核处理有符号数时就是以补码形式进行处理的,这里怎么办呢?

可以这样办:

当matlab产生一组有符号数据后,确定了在FPGA中时使用N位存储处理,则在matlab中再增加一步转换即可:

data_signed=[……];%得到有符号数组

sign=(data_signed<0);%得到与数组对应的符号数组,当数组元素小于0时其值为1,反之为0

data_signed=data_signed+sign.*2^N;%当数组元素小于1时则加上2^N,转化为补码形式

 

参考:

https://blog.youkuaiyun.com/xlhcgd/article/details/48054891

### 有符号大整数的加减乘除运算实现 对于有符号的大整数(即可以表示正数和负数),其加减乘除运算是基于二进制补码来处理的。以下是针对每种基本运算的具体实现方式。 #### 加法操作 当两个带符号的大整数相加时,如果两者的符号相同,则可以直接将它们绝对值相加并保留原始符号;若符号不同,则需先计算两者绝对值得差再赋予较大数值的那个符号作为最终结果[^1]。 ```c void addBigInt(BigInt* result, BigInt* a, BigInt* b){ if(a->sign == b->sign){ // 同号情况下的简单累加 sumPositive(result,a,b); result->sign=a->sign; }else{ // 异号情况下取绝对值较大的那个数的符号 subtractPositive(result,(a->absValue>b->absValue)?a:b, (a->absValue<b->absValue)?a:b); result->sign=(a->absValue>=b->absValue)?a->sign:b->sign; } } ``` #### 减法操作 执行减法实际上就是加上被减数相反数的过程,在这里可以通过改变待减去项(`b`)的符号来进行转换成加法问题求解[^2]: ```c void substractBigInt(BigInt* result,BigInt*a ,BigInt*b ){ b->sign=!b->sign; // 反转b的符号使其成为-a+b的形式 addBigInt(result,a,b); b->sign=!b->sign; // 记得恢复原来的符号状态以免影响后续调用 } ``` #### 乘法操作 为了完成带有符号的大整数之间的乘积计算,可先忽略掉所有参与因子上的符号标记只做无符号版本的操作之后依据原输入参数中的总共有奇偶数量个'-'决定最后输出应携带怎样的标志位[^3]: ```c void multiplyBigInt(BigInt*result ,BigInt*a ,BigInt*b){ unsignedMultiplyBigInt(result,a,b); // 执行不考虑符号的实际多位数相乘过程 bool signResult=((a->sign==false && b->sign==true)||(a->sign==true&&b->sign==false))?true:false; result->sign=signResult; } ``` #### 除法操作 同样地,在进行除法规则设计上也是遵循着去除原有各部分所附带有的指示符后再依照常规方式进行商值获取工作,而余数保持不变即可[^4] : ```c void divideBigInt(BigInt* quotient,BigInt* remainder,BigInt* dividend,BigInt* divisor){ unsignedDivideBigInt(quotient,remainder,dividend,divisor); if(dividend->sign!=divisor->sign) quotient->sign=true; else quotient->sign=false; remainder->sign=dividend->sign; } ``` 以上代码片段展示了如何利用C语言实现四个主要类型的算术运算——加、减、乘以及除于任意长度大小范围内存在正负属性差异的数据对象之间相互作用的方法论框架结构.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值