我有一些浮點數的文件,我有問題找出他們的確切編碼。我已經嘗試了幾種方法轉換爲標準雙精度值,但沒有太多運氣。我知道這些值應該轉換爲什麼,但需要一種方法直接從文件中提取。惠普2114/15/16浮點轉換
這些是HP-1000(HP21xx)系列浮點值。類似於48位帕斯卡,但不一樣。
除了一些舊的,不可靠的文檔(無法使用聲明的格式進行轉換)以及來自quadibloc.com的格式列表,我什麼也沒有發現。從quadibloc格式給出如下:
(Note, big-endian order)
MSb: mantissa sign (says it's 2s complement)
39 bits: mantissa
7 bits: exponent
1 bit: exponent sign
的其他文件不清晰,但似乎說這是所有二進制補碼。 我試過了我發現的Pascal轉換代碼,但它甚至沒有接近。 (將指數符號移到字節的高位之後)。
實施例,轉換使用模擬一個HP-1000 PPC:
A7EB851EB90A -22.02
A870A3D70A0A -21.89
A8AE147AE20A -21.83
A8E147AE140A -21.78
A9666666670A -21.65
AC70A3D70A0A -20.89
ACC28F5C290A -20.81
ACCCCCCCCC0A -20.8
AE70A3D70B0A -20.39
AEB851EB850A -20.32
這是隻從一個文件。我至少有100個這些文件要從中提取。
任何想法?當然會感激。
編輯:我想我應該說我在用什麼語言。在這種情況下,它是C#。至於其他數據,我有很多。這裏有更多的例子,這些例子包括負指數,至少在轉換成小數時。
400000000002 1
43851EB85204 2.11
451EB851EB04 2.16
4C7AE147AE04 2.39
4EC4EC4EC5F3 4.8076923077E-03
519999999A04 2.55
5838B6BE9BF3 5.3846153846E-03
5B851EB85202 1.43
5BD70A3D7108 11.48
5C7AE147AE08 11.56
5E51EB851E08 11.79
5FD70A3D7108 11.98
62E147AE1508 12.36
64A3D70A3E08 12.58
666666666702 1.6
67AE147AE202 1.62
6B204B9E54F3 6.5384615385E-03
733333333302 1.8
762762762AF3 7.2115384616E-03
794DFB4619F3 7.4038461538E-03
7C74941627F3 7.5961538465E-03
7E07E07E14F3 7.6923076925E-03
以前應該包括正數。
嘗試了這些建議,但在C#中。結果大不相同。我甚至分解了計算的部分,但是與建議中給出的數字相比,我得到的數字非常高。這是擴展位的代碼。
Int64[] test_data = new Int64[] {
0xA7EB851EB90A, 0xA870A3D70A0A, 0xA8AE147AE20A, 0xA8E147AE140A,
0xA9666666670A, 0xAC70A3D70A0A, 0xACC28F5C290A, 0xACCCCCCCCC0A,
0xAE70A3D70B0A, 0xAEB851EB850A, 0x400000000002, 0x43851EB85204,
0x451EB851EB04, 0x4C7AE147AE04, 0x4EC4EC4EC5F3, 0x519999999A04,
0x5838B6BE9BF3, 0x5B851EB85202, 0x5BD70A3D7108, 0x5C7AE147AE08,
0x5E51EB851E08, 0x5FD70A3D7108, 0x62E147AE1508, 0x64A3D70A3E08,
0x666666666702, 0x67AE147AE202, 0x6B204B9E54F3, 0x733333333302,
0x762762762AF3, 0x794DFB4619F3, 0x7C74941627F3, 0x7E07E07E14F3
};
private void Checkit()
{
Byte[] td = new Byte[6]; // 6 byte array for reversed data
Byte[] ld = new Byte[8]; // 8 byte conversion array
for (Int32 i = 0; i < test_data.Length; i++) // Loop through data
{
ld = BitConverter.GetBytes(test_data[i]); // Get value as byte array
for (Int32 j = 0; j < 6; j++) // Copy the bytes in reverse
td[5 - j] = ld[j];
// Go test them
Console.WriteLine("{0:X6} --> {1:E}", test_data[i], Real48ToDouble(ref td));
}
}
Double Real48ToDouble(ref Byte[] realValue)
{
// Values are using input value of A7EB851EB90A and 7E07E07E14F3
if (realValue[0] == 0)
return 0.0; // Null exponent = 0
Byte[] b = new Byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; // 64 bit byte array
for (Int32 i = 0; i < 5; i++) // Copy over the 48 bit info
b[4 - i] = realValue[i];
Int64 mant = BitConverter.ToInt64(b, 0); // 0x000000A7EB851EB9 - Get mantissa with sign
// 0x0000007E07E07E14
Int32 expo = realValue[5]; // 0x0000000A - Grab the exponent
// 0x000000F3
Int32 mant_sign = (Int32)(mant >> 39); // 0x00000001
// 0x00000000
// sign extend mantissa from 40 to 64 bits, then take absolute value
mant = (Int64)((mant^(1L << 39)) - (1L << 39)); // 0xFFFFFFA7EB851EB9 - First calc
// 0x0000007E07E07E14
mant = Math.Abs(mant); // 0x00000058147AE147 - Make absolute
// 0x0000007E07E07E14
// convert mantissa to floating-point
Double fmant = mant * Math.Pow(2, -39.0); // 0.68812499999876309 - Second calc
// 0.98461538463743636
// rotate exponent field right by 1 bit
expo = (expo >> 1) | ((expo & 1) << 7); // 0x00000005
// 0x000000F9
// sign extend exponent from 8 to 32 bits
expo = ((expo^(1 << 7)) - (1 << 7)); // 0x00000005
// 0xFFFFFFF9
// compute scale factor from exponent field
Double scale = Math.Pow(2, expo); // 32.0 - Scale
// 0.0078125
// scale mantissa, and apply sign bit for final result
Double num = fmant * scale; // 22.019999999960419 - Make the final abs number
// 0.0076923076924799716
return (mant_sign != 0) ? (-num) : num; // -22.019999999960419 - Return with sign
// 0.0076923076924799716
}
上面更改的代碼 上面的代碼現在正常工作。
從[浮點格式](HTTP:/ /www.oneonta.edu/faculty/zhangs/csci201/general%20Floating%20Point%20Format.htm):*浮點數以2的補碼尾數開始,然後結束w第七位指數,後面是指數的符號,當數字是負數時,兩者都不會互補。浮點數可以佔用兩個或三個16位字,具體取決於它們是單精度還是雙精度。* –
@Andy前導七個字節看起來是二進制補碼尾數。看一下-20.8,經過適當的縮放後,轉換爲'ACCCC ...'作爲二進制補碼。我遇到的問題是弄清楚最後一個字節'0A'如何映射到指數。你有不同的binade的額外的示例值?這大概會澄清指數編碼。 – njuffa
我的意思是「領先*五*字節」代表二進制補碼尾數。所以這個值是('0xACCCCCCCCC'/2^39)* 2^expo。 – njuffa