无符号数除法
- 格式:doc
- 大小:65.50 KB
- 文档页数:3
一、CPU只会根据输入信号进行逻辑运算,在硬件级别是没有有符号无符号的概念,运算结束会根据运算前的信号和输出信号来设置一些标志位,是不是有符号由写程序的人决定,标志位要看你把操作数当有符号还是无符号来选择,就像内存中的数据,你可以按照需要来解析,原始数据在那里,你要按什么数据格式来解析在于自己的选择,所以玩汇编的要做到心里有数,加减法只有一套指令,因为这一套指令同时适用于有符号和无符号。
下面这些指令:mul div movzx … 是处理无符号数的,而这些:imul idiv movsx … 是处理有符号的。
举例来说:内存里有一个字节x 为:0x EC ,一个字节y 为:0x 02 。
当把x,y当作有符号数来看时,x = -20 ,y = +2 。
当作无符号数看时,x = 236 ,y = 2 。
下面进行加运算,用add 指令,得到的结果为:0x EE ,那么这个0x EE 当作有符号数就是:-18 ,无符号数就是238 。
所以,add 一个指令可以适用有符号和无符号两种情况。
(呵呵,其实为什么要补码啊,就是为了这个呗,:-))乘法运算就不行了,必须用两套指令,有符号的情况下用imul 得到的结果是:0x FF D8 就是-40 。
无符号的情况下用mul ,得到:0x 01 D8 就是472 。
二、C又是可怕的,因为它把机器层面的所有的东西都反应了出来,像这个有没有符号的问题就是一例(java就不存在这个问题,因为它被设计成所有的整数都是有符号的)。
为了说明c的可怕特举一例:#include <stdio.h>#include <string.h>int main(){int x = 2;char * str = "abcd";int y = (x - strlen(str) ) / 2;printf("%d\n",y);}结果应该是-1 但是却得到:2147483647 。
在Verilog中,无符号数运算通常使用unsigned数据类型。
unsigned数据类型用于表示非负整数,它支持加法、减法、乘法和除法等基本算术运算。
以下是一个简单的Verilog代码示例,演示了如何进行无符号数运算:module adder_subtractor;reg [3:0] a, b; // 定义4位无符号寄存器a和bwire [3:0] sum, diff; // 定义4位无符号总线和差分线// 4位加法器assign sum = a + b;// 4位减法器assign diff = a - b;initial begina = 4'b0000; // 初始化为0b = 4'b0001; // 初始化为1#5 $display("Sum = %d, Diff = %d", sum, diff); // 输出结果a = 4'b1010; // 修改a的值b = 4'b0001; // 保持b的值不变#5 $display("Sum = %d, Diff = %d", sum, diff); // 输出结果endendmodule在上面的代码中,我们定义了两个4位无符号寄存器a和b,以及两个4位无符号总线sum和diff。
通过assign语句,我们将a + b的结果赋值给sum,将a - b的结果赋值给diff。
在initial块中,我们初始化了寄存器a和b的值,并使用#5 $display语句输出了两次运算的结果。
需要注意的是,无符号数运算可能会产生溢出或下溢的情况。
因此,在实际应用中,我们需要仔细考虑无符号数运算的边界情况,并采取相应的措施来处理溢出或下溢的情况。
汇编div指令的用法汇编语言中的div指令主要用于进行除法运算。
它将一个无符号数或有符号数除以一个操作数,并将商存储在寄存器中。
在不同的汇编语言中,div指令和操作数的寄存器名称可能会有所不同。
下面将以x86汇编语言为例,详细介绍div指令的用法。
在x86汇编语言中,div指令用于执行无符号除法运算。
它的语法通常形如:```div 原操作数```其中,原操作数可以是寄存器、内存地址或立即数。
div指令默认使用的除数寄存器是eax,即将eax中的值除以原操作数,并将商存储在eax中,余数存储在edx中。
在执行div指令之前,需要确保eax中含有一个有效的无符号数。
而edx寄存器在div之前应该被清零,以确保结果正确。
div指令执行时,会检测除数是否为0。
如果除数为0,程序将会引发一个除以零的异常。
在进行有符号数除法运算时,x86汇编语言中还提供了idiv指令。
其语法和用法与div指令非常类似,但它执行的是有符号除法运算。
例如:```idiv 原操作数```idiv指令也会默认使用eax作为除数寄存器,商存储在eax中,余数存储在edx中。
除了指令本身的语法和用法,还需要关注div指令的影响和限制。
首先,div指令会修改eax和edx寄存器中的值,所以在使用div指令之前,应该进行必要的寄存器保存。
其次,div指令只能用于无符号整数或带符号整数的除法运算,而不能进行浮点数的除法运算。
此外,由于寄存器的限制,除数不能为32位操作数,而必须是16位操作数。
在实际编程中,可以利用div指令实现各种除法运算,如求解商和余数、计算特定位数的小数等。
通过合理地使用div指令,可以使代码更加高效和简洁。
总之,div指令在汇编语言中扮演着十分重要的角色,它用于进行除法运算并将商存储在寄存器中。
div指令的使用方法和语法会因不同的汇编语言而有所差异,但其基本功能和特性是相似的。
通过充分了解和熟练运用div指令,可以帮助我们更好地理解和编写汇编语言程序。
8086中32位数据除法8086是一种16位的微处理器,但它也支持32位的数据操作。
本文将着重介绍8086中的32位数据除法。
在8086中,32位数据除法是通过使用特定的指令来完成的。
这个指令是DIV,它用于将一个32位的无符号数除以一个8位或16位的无符号数。
DIV指令的语法如下:DIV 操作数其中,操作数可以是一个8位或16位的寄存器或内存单元。
DIV 指令执行后,会将32位被除数寄存器DX:AX的值除以操作数,并将商保存在AX寄存器中,余数保存在DX寄存器中。
在执行DIV指令之前,需要将被除数加载到DX:AX寄存器中。
如果被除数是一个32位的数,则将高16位加载到DX寄存器中,低16位加载到AX寄存器中。
如果被除数是一个64位的数,则需要进行适当的处理,将高32位加载到DX寄存器中,低32位加载到AX寄存器中。
在8086中,由于寄存器的大小限制,被除数和除数的位数都有一定的限制。
被除数最多为32位,除数最多为16位。
如果被除数为64位,需要通过多次除法运算来计算商和余数。
在进行32位数据除法时,需要注意以下几点:1. 被除数的高16位必须小于或等于除数。
如果被除数的高16位大于除数,则会触发一个异常,导致程序中断。
2. 除数不能为0。
如果除数为0,则会触发一个除以0的异常,导致程序中断。
3. 除法运算的结果必须在合理的范围内。
如果商或余数超出了16位的范围,则会导致溢出,结果将不正确。
除了DIV指令,8086还提供了一些其他的指令来执行32位数据除法。
其中之一是IDIV指令,用于执行带符号的32位数据除法。
IDIV指令的使用方法与DIV指令类似,只是它将被除数和除数都视为带符号数进行计算。
在使用DIV指令或IDIV指令进行32位数据除法时,需要考虑性能和精度的平衡。
较大的除数会导致除法运算的时间变长,较小的除数可能会导致精度损失。
因此,在实际应用中,需要根据具体情况选择合适的除数。
总结一下,8086中的32位数据除法是通过DIV指令或IDIV指令来完成的。
mul指令和div指令
mul指令和div指令是x86汇编语言中的算术指令,用于执行乘
法和除法操作。
mul指令用法:
mul指令用于无符号数乘法运算,将目标寄存器的值乘以另一个寄存器
或内存单元的值,并将结果存储在一对寄存器中。mul指令支持的操作
数包括寄存器和内存单元,但是结果只能存储在一对寄存器中(如eax
和edx)。
例如,执行eax和ebx的乘法操作:
mul ebx
div指令用法:
div指令用于无符号数除法运算,将目标寄存器的值除以另一个寄存器
或内存单元的值,并将商存储在一个寄存器中,余数存储在另一个寄
存器中。div指令支持的操作数包括寄存器和内存单元,但是除数必须
是非零值。
例如,执行eax除以ebx操作:
div ebx
需要注意的是,使用mul和div指令时需要注意数据类型和数值
范围的问题,否则可能会出现数据溢出和错误的结果。
CDQ指令及其相关除法
CDQ(Convert Double to Quad的缩写,意为将双字数据扩展为四字),⼤多出现在除法运算之前. 它实际的作⽤只是把EDX的所有位都设成EAX最⾼位的值.
也就是说,当EAX <80000000, EDX 00000000 (80000000以下是正数,原码0开头); 当EAX >= 80000000, EDX 则为FFFFFFFF).
除法分为DIV(⽆符号)和IDIV(有符号)
DIV (unsigned divide) ⽆符号数除法
格式:DIV SRC
执⾏的操作:
字节操作:16位被除数在AX,8位除数为源操作数,结果的8位商在AL中,8位余数在AH中。
表⽰为
(AL)<-(AX)/(SRC) 的商 (AH) <-(AX)/(SRC) 的余数
字操作:32位被除数放在DX,AX中。
其中DX为⾼位字,16位除数为源操作数,结果的16位端在AX中,16位余数在DX中。
表⽰为 (AX)<-(DX,AX)/(SRC) 的商 (DX)<-(DX,AX)/(SRC) 的余数
双字操作:64位被除数在EDX,EAX中,其中EDX为⾼位双字,32位除数为源操作数,结果的32位商在EAX中,32位余数在EDX中,表⽰为 (EAX)<-(EDX,EAX)/(SRC) 的商 (EDX)<-(EDX,EAX)/(SRC) 的余数。
商和余数均为⽆符号数。
IDIV 带符号除法指令
格式:IDIV SRC
执⾏的操作:与DIV相同,但操作数必须是带符号的数,商和余数也都是带符号的数,且余数的符号和被除数的符号相同。
加法运算减法运算乘法运算除法运算1. 加法运算规则:0+0=00+1=11+0=11+1=0(有进位)例:计算10110110B+00101100B解:进位 1111 1000被加数 1011 0110加数 0010 1100和 1110 0010所以,10110110B+00101100B=11100010B2. 减法运算规则:0-0=01-0=11-1=00-1=1(有借位)例:计算11000100B-00100101B解:借位 0111 1110被减数 1100 0100减数 0010 0101差 1001 1111所以,11000100B-00100101B=10011111B3. 乘法运算规则:0×0=00×1=01×0=01×1=1二进制乘法的运算方法与十进制乘法的运算方法类似。
例:计算1100B×1001B解:按照十进制乘法的运算过程,有1100× 100111000000000011001101100所以,1100B×1001B=1101100B另外,乘法运算也可以采用加法和左位的方法实现,算法如下:1)令部分积=0;2)如果乘数的当前位=1,则将被乘数加到部分积上,否则不加;3)将被乘数左移1位;4)转到2),直到乘数的所有位都检查完。
下面,用加法和左移的方法重做上例。
所以,1100B×1001B=1101100B 。
可以看出,这与前一种方法的结果是一样的,但后一种方法更便于计算机实现,因为移位是计算机的一种最基本的操作。
4. 除法运算除法是乘法的逆操作,所以除法运算可以采用减法和向右移位的方法实现,算法如下:1)令部分商=0,并将除数右面补m 个0(m 为被除数位数与除数位数之差);2)若被除数≥除数,则被除数减去除数,部分商左移入一个1;若被除数<除数,则不减,部分商左移入一个0;3)将除数右移1位;4)m =m -1,若m =0,则结束,否则转第2步;5)结束后,被除数的值为结果的余数部分,部分商的值为结果的商。
long long和unsigned int 运算在计算机编程中,数据类型是用于表示不同种类数据的容器。
long long 和unsigned int是两种常见的长整型数据类型,它们在数值范围和运算规则上有一定差异。
本文将详细介绍这两种数据类型的特点,以及在实际编程中如何正确使用它们。
首先,我们来了解long long和unsigned int的基本概念。
long long是一种双精度长整型数据类型,它在C/C++等编程语言中使用。
它的数值范围为负2^63到2^64-1,即-9223372036854775808到9223372036854775807。
unsigned int是一种无符号整数类型,也表示长整型。
它的数值范围为0到2^32-1,即0到4294967295。
接下来,我们分析一下long long和unsigned int的运算规则。
1.加法运算:- long long的两数相加,结果可能溢出,需要注意数值范围。
- unsigned int的两数相加,结果不会溢出,但请注意数值范围。
2.减法运算:- long long的两数相减,结果可能溢出,需要注意数值范围。
- unsigned int的两数相减,结果不会溢出,但请注意数值范围。
3.乘法运算:- long long的两数相乘,结果可能溢出,需要注意数值范围。
- unsigned int的两数相乘,结果不会溢出,但请注意数值范围。
4.除法运算:- long long的两数相除,结果可能溢出,需要注意数值范围。
- unsigned int的两数相除,结果不会溢出,但请注意数值范围。
5.取模运算:- long long的两数取模,结果可能溢出,需要注意数值范围。
- unsigned int的两数取模,结果不会溢出,但请注意数值范围。
6.比较运算:- long long和unsigned int的比较运算符(如>、<、==等)均可正常使用,但请注意数值范围。
在Verilog HDL语言中虽然有除的运算指令,但是除运算符中的除数必须是
2的幂,因此无法实现除数为任意整数的除法,很大程度上限制了它的使用领域。
并且多数综合工具对于除运算指令不能综合出令人满意的结果,有些甚至不能给
予综合。对于这种情况,一般使用相应的算法来实现除法,分为两类,基于减法
操作和基于乘法操作的算法。[1]
基于减法的除法器的算法:
对于32的无符号除法,被除数a除以除数b,他们的商和余数一定不会超
过32位。首先将a转换成高32位为0,低32位为a的temp_a。把b转换成高
32位为b,低32位为0的temp_b。在每个周期开始时,先将temp_a左移一位,
末尾补0,然后与b比较,是否大于b,是则temp_a减去temp_b将且加上1,
否则继续往下执行。上面的移位、比较和减法(视具体情况而定)要执行32次,
执行结束后temp_a的高32位即为余数,低32位即为商。
Verilog HDL 代码
/*
功能: 32位除法器
输入参数: 被除数a,除数b
输出参数: 商yshang,余数yyushu
备注: 采用移位、比较和减法(从高位开始)实现的除法运算
本例实现的是32位除法器的例子
*/
module division(a,b,yshang,yyushu);
input[31:0] a; //被除数
input[31:0] b; //除数
output[31:0] yshang; //
output[31:0] yyushu; //
reg[31:0] yshang;
reg[31:0] yyushu;
reg[31:0] tempa;
reg[31:0] tempb;
reg[63:0] temp_a;
reg[63:0] temp_b;
always @(a or b)
begin
tempa <= a;
tempb <= b;
end
integer i;
always @(tempa or tempb)
begin
temp_a = {32'h00000000,tempa}; //
temp_b = {tempb,32'h00000000}; //
for(i = 0;i < 32;i = i + 1) //32次循环
begin
temp_a = {temp_a[62:0],1'b0}; //左移一位
if(temp_a[63:32] >= tempb) //注意:temp_a的高32位于tempb比较,不
是与temp_b比较
temp_a = temp_a - temp_b + 1'b1; //加1表示商加1
else
temp_a = temp_a;
end
yshang <= temp_a[31:0];
yyushu <= temp_a[63:32];
end
endmodule
波形仿真与测试结果
图1 32位无符号数除法功能仿真图
从仿真图1中可以得出,运算速度很快,但是这是基于占用大量LE的基础
上的,在FPGA的设计中,要关心两个参数:逻辑资源的占用率和速度。这种采
用组合逻辑实现的除法器以耗费大量LE来获取速度优势的设计在被除数小于8
位时应用还可以,大于8位,就得改变算法。
图2 32位无符号除法的分析综合报告
参考文献:
[1] 周殿凤,王俊华.基于FPGA的32位除法器设计[J].信息化研究,2010,36
(3):26-28