早就想知道浮點數的存儲原理; 從 Single 開始理解.
Single(單精度浮點數 - 32 位):
s e f
1 8 23
如浮點數: 13.625 (1*101 + 3*100 + 6*10-1 + 2*10-2 + 5*10-3)
其二進制表示是: 1101.101(1*23 + 1*22 + 0*21 + 1*20 + 1*2-1 + 0*2-2 + 1*2-3)
尾數規范化: 1101.101 = 1.101101 * 23
尾數規范化以後, 都可成為 1.xxxxx... 的樣子, 所以為節省空間, "點" 前面的 1 就無須儲存了.
這樣可以知道此數的指數(e)是 00000011(十進制的 3)、尾數(f, 或叫系數) 是 101101(省去了前面的 1. 回算時必須加上)
符號位(s)只占一個二進制位, 非常簡單: 0 是正, 1 是負.
指數(e)在這裡還有一個規則: 實際儲存 = e+127; 這是為了協調指數的正負.
重新落實最後的結果:
s: 應該是 0, 這裡是個正數;
e: 應該是: 10000010, 這對應 10 進制的 130(3+127);
f: 10110100000000000000000, 尾數占 23 位.
結果應該是: 01000001010110100000000000000000
測試下:
{查看二進制的函數}
function ToBin(p: PByteArray; b: Integer): string;
var
i,j: Integer;
begin
Result := StringOfChar('0', b * 8);
for i := 0 to b - 1 do for j := 0 to 7 do
if Odd(p^[b-1-i] shr j) then Result[i*8 + 8 - j] := '1';
end;
{測試一}
procedure TForm1.Button1Click(Sender: TObject);
var
f1,f2: Single;
s1,s2: string;
begin
f1 := 13.625;
f2 := -13.625;
s1 := ToBin(@f1, SizeOf(f1));
s2 := ToBin(@f2, SizeOf(f2));
Memo1.Lines.Add(s1); //01000001010110100000000000000000
Memo1.Lines.Add(s2); //11000001010110100000000000000000
end;
{測試二}
procedure TForm1.Button2Click(Sender: TObject);
var
f1,f2: Single;
begin
asm
mov f1, 01000001010110100000000000000000B
mov f2, 11000001010110100000000000000000B
end;
ShowMessageFmt('%g, %g', [f1,f2]); //13.625, -13.625
end;
其他浮點數的儲存規則:
Double 或 Real(雙精度浮點數 - 64 位):
s e f
1 11 52
Extended(擴展精度浮點數 - 80 位):
s e i f
1 15 1 63
Real48(已經淘汰的 48 位浮點數):
s f e
1 39 8