標籤:mainframe assembler cobol comp-1 comp-2 dump
在從事大型主機的工作中,很多時候我們所做的都是讀dump,然後反向找出VSAM/QSAM資料集中的不當記錄,尤其當資料集很大的時候,精確定位一條記錄很是不便。。。而這裡介紹的利用浮點數反向尋找就是一個捷徑(比如:我們在dump裡看到X‘C411570A‘,如果能快速算出-4439.039,再在資料集中搜尋-4439.039,相信很容易就能鎖定到你想要的目標記錄),下面我們解析下,大型主機是如何儲存浮點數及我們又怎樣快速算出其對應的十進位資料。
我們知道在COBOL裡:
COMP-1是用來定義單精確度浮點數的,佔四個位元組(對應於HLASM/mainframe assembler裡的E定義)
COMP-2是用來定義雙精確度浮點數的,佔八個位元組(對應於HLASM/mainframe assembler裡的D定義)
具體內部儲存見:
解析如下:
第0位(最左邊的bit位為第0位,以此類推)是符號位,0為正,1為負。
第1—7位是指數位,初始值為X‘40‘,如果小數點左移1位,則初始值加1,為X‘41‘;如果右移1位,則減1,為X‘3F‘。
第8—31/8—63位是尾數位,也可以說是組合位(8—31是針對COMP-1,8—63針對COMP-2)。
1.主機是以純小數並且十分位不為0的形式儲存資料的
地址 記憶體資料 常量名 常量數值
000064 427B74BC 14 A DC E‘123.456‘
000068 427B0000 15 B DC E‘123‘
00006C 4074BC6A 16 C DC E‘.456‘
000070 C27B74BC 17 X DC E‘-123.456‘
000074 00000000
000078 427B74BC6A7EF9DB 18 Y DC D‘123.456‘
A,B和C我們都定義成常量,並且可以把A看成是B + C之和
B: 123 = X‘7B‘按照要求應該變為0.7B * 16^2,由於指數為+2,所以指數的bit位就變成了X‘40‘+X‘2‘=X‘42‘,即記憶體為427B0000
C: 0.456=X‘0.74BC6A7EF9DB‘=0.74BC6A7EF9DB * 16^0,其本身已經符合要求了,所以記憶體為4074BC6A(由於C最多四個位元組,後面的儲存不了自動捨棄,這和我們常說的小說點後精確到多少位含義是一樣)
電腦在進行加減之前,首先要保證指數一致,然後再保證小數點對齊。要理解這個,我們可以參考下十進位,比如100*10^1+ 0.008*10^2,一般的演算法為:100*10^1+ 0.008*10^2 = 1000 + 0.8 = 1000.8
其實這裡隱含的約束也是先把指數變成一樣,然後小數點對齊(只是這裡指數部分為10^0)。
其實電腦也是這麼做的:
1.先把前兩位(指數位)變成相同:4074BC6A -> 41074BC6 -> 420074BC
2.然後再進行C+B=A的計算:420074BC+ 427B0000 = 427B74BC
再來看下X和Y,X是A的相反數,Y和A只是精度不同
X是負數,所以其記憶體第一個bit位是1。
Y被定義成雙精確度浮點數類型(COMP-2),可以看出A和Y的記憶體資料僅僅是精度不同而已。
2.剖析一個記憶體資料,比如:C211570A
1.由於第一個bit是1,所以它是個負數,
2.由於指數位是X‘42‘,即後面三個位元組中的11為整數部分,570A為小數部分
3.整數部分11變成十進位為17
4.小數部分0.570A變成十進位為0.339996337890625,約等於0.34
(這裡給個百度連結,十進位/十六進位轉換工具:http://www.baidu.com/s?tn=baiduhome_pg&ie=utf-8&bs=Fraction&f=8&rsv_bp=1&rsv_spt=1&wd=01+%E5%8D%81%E5%85%AD%E8%BF%9B%E5%88%B6%E8%A1%A8%E7%A4%BA&rsv_sug3=9&rsv_sug=0&rsv_sug1=9&rsv_sug4=688&inputT=10402)
5.即這個數字為-17.34
3.怎麼從一個十六進位資料快速反推出我們想要的十進位
1)快速反推(由十六進位推算出十進位):
C211570A =(-X‘11570A‘/16^6)*16^2
= -X‘11570A‘/16^4
= -1136394/65536
= -17.34
C411570A = (-X‘11570A‘/16^6)* 16^4
= -X‘11570A‘/16^2
= -1136394/256
= -4439.039
2)快速正推(由十進位推算出十六進位):
17.34 = 0.1734 * 10^2
= 1734/10^2
= X‘6C6‘/ X‘64‘
= (X‘6C60000‘/ X‘64‘)*(1/X‘10000‘)
= 11570A*(1/ X‘10000‘)
這裡為什麼先讓被除數乘X‘10000‘,是因為筆記本內建的電腦在進行16進位除法的時候,只顯示整數部分.實際上,電腦也是沒法表示16進位的小數部分的,因為我們平時說的小數點,都是針對十進位的,又有誰見過16進位的小數點長什麼樣子?
所以記入記憶體時再縮小X‘10000‘倍即可:X‘4211570A‘(如果不縮小應該是X‘4611570A‘)
以上方法的總體思想都是把除數和被除數都變成整數,然後再進行運算。
有疑問請聯絡:QQ349106216
COMP-1及COMP-2內部儲存解析