有符號數和無符號數在計算機中的存儲方式以及在Verilog中的運用($signed函數)


#0.計算機組底層的電路只認識0和1,並沒有任何數制和邏輯的概念。

#1.首先在計算機中數字分為 定點數和浮點數; 定點數又分為定點整數和定點小數;定點整數有無符號和有符號兩種 ;這里主要討論無符號數和有符號數在計算機中是如何存儲以及在VerilogHDL語言中如何使用。
#2.VerilogHDL語言中除了integer類型之外的所有數據類型默認都是無符號類型;
#3.符號擴展是用於兩個運算操作數的位數不一樣的時候,進行位數的統一的操作;這里只討論相等位數;

 

一,無符號數
#如果要進行兩個無符號數之間的大小比較該如何進行;首先應該注意的就是無符號數在計算機中是以原碼形式存儲的;原碼存儲就意味着這種表示方式下,任何計算結果都會是無符號數,這是因為1.存儲位數是一定的所以最高位進位會被舍棄掉。2.如下圖一樣,所有加減的本質就是繞圈順時針逆時針轉。既然是這樣,就是說直接用相減看差的方式是不可能得出正確的結果的;

如:*這時候會想:因為Verilog中的數據默認是用無符號形式存儲的,因此這個可以直接進行比較大小
if(A - B > 0) C = 1;
else C = 0;
但實際上在無符號數中計算結果永遠都是正的!所以這個不行*

 

#所以真正真確的方式應該是從本質入手,也就是說兩個數相減或相加,只要有溢出也就是最高位有進位那么結果一定是不對的,從這里入手在考慮實現細節。
module comparator(
input [3:0]A,
input [3:0]B,
output reg [3:0]C
);

reg [4:0]tempA;
reg [4:0]tempB;
reg [4:0]tempresult;
always@()begin
tempA = {0, A}; //對無符號數進行0擴展,實現標志位
tempB = {0, B};
tempresult = tempA - tempB;
if(tempresult[4] == 0)begin
C = 1; //被減數比較大
end
else if(tempresult[4] == 1)begin //這是有進位了,但是實際是被舍棄的
C = 0; //減數比較大
end

end
endmodule


#BUT!在Verilog中已經有函數可以直接實現這種無符號數之間的轉換;
module comparator(
input [3:0]A,
input [3:0]B,
output reg [3:0]C

);

always@()begin
if($unsigned(A) > $unsigned(B)) C = 1; //剛才說過因為Verilog中的數默認是無符號數,因此可以這個函數也可以不寫;;但是一定不能寫成是相減的形式
else C = 0;
end

endmodule

 

二,有符號數
#這里需要理解的是,有符號數有兩種存儲方式:原碼形式和補碼形式;但是幾乎所有的計算機都使用二進制補碼表示法來表示存儲於n為存儲單元的有符號整數。具體一些:假設4‘b1001是一個有符號數,用原碼形式4’b1001=-1;但是用補碼形式的話4'b1001=-7.在補碼表示法中,對一個正數是直接用原碼來表示,只有負數采用補碼來表示,這是因為補碼(~B+1)實際上是對負數取絕對值的運算,比如4‘b1001在補碼下實際值為-7(還不理解就去查一下補碼的表),對其進行取反加一就變成4'b0111=+7;*  (實際上有符號數的表示就是用補碼來表示的,所以以后的所有情況都只考慮是在補碼表示法下的用法)

#這里在說明一下補碼表示法下的運算,注意這里的“補碼”是一種表示法!不是轉換方式,具體來講就是”正數不變,負數取反加一“;就這么簡單。先看一下加法運算:如果4’b0110 + 4'b1001 就直接進行運算 = 4‘b1111;而實際上原式子用十進制寫的話就是 6 + (-7) = -1;而4’b1111在補碼表示下就是-1! 在看一下減法運算:如果4'b0110 - 4'b1001這時候就需要對被減數進行取反加一操作了,也就是對其加上絕對值~這是什么意思呢? 先看一下原式子的十進制表示:6 - (-7) = 6 + 7;所以實際上之所以要對被減數進行取反加一就是為了”負負得正“。接下來就很簡單:4‘b0110 + 4'b0111 = 4'b1101; 會發現這時候計算結果4'b1101補碼形式下等於-3,而正確應該是6+7 = 13;為什么呢? 對,是因為溢出了。因為4位有符號數的表示范圍:0~7 -1~-8; 但是本質上應該可以理解了。


這里不具體談如何從最底層進行無符號數的大小比較,主要是因為Verilog中函數已經實現了具體的功能;這里又一些細節:

對兩個有符號數。必須考慮兩個數是同號還是異號:
A 、 對兩個同符號數。因其相減不會溢出,即OF=0。 SF=0:被減數大於減數
SF=1:被減數小於減數
B 、如果比較的兩個數符號不相同,此時就有可能出現溢出 ·若OF =0 (即無溢出),則有:
如果被減數大於減數,SF =0,
如果被減數小於減數,SF =1;
如果被減數等於減數,sF =0,同時ZF =1;
·若OF =1(有溢出) .則:
如果被減數大於減數,SF =1
如果被減數小於減數,SF =0。
若OF ⊕SF=0,則dest >src;
若OF ⊕SF=1,則dest <src 。

//比較兩個有符號數的大小
module comparator(
input [3:0]A,
input [3:0]B,
input [3:0]C

);

always@()begin
if($signed(A) > $signed(B)) C = 1; //同樣這里不能寫成減法的形式
else C = 0;

end
endmodule

 

 

所以這里需要記住的就是:

有符號數的 (A > B) 和 (A-B>0)是不一樣的,因為提供有符號類型的人已經幫你寫好了如何進行比較的算法,所以用正確的方式去用,但是如果自己實現的話,就要考慮很多情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM