如何将8字节十六进制转换为实数

问题描述 投票:0回答:1

我正在研究文件转换器。我以前从未做过使用二进制文件读取的任何事情。有许多转换器可用于此文件类型(gdsII to text),但没有一个我可以找到的swift。

我已经使所有其他数据类型工作(2字节int,4字节int),但我真的很难实际数据类型。

来自规范文件:http://www.cnf.cornell.edu/cnf_spie9.html

实数不以IEEE格式表示。浮点数由三部分组成:符号,指数和尾数。数字的值定义为(尾数)(16)(指数)。如果“S”是符号位,“E”是指数位,“M”是尾数位,则8字节实数具有格式

SEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM
MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM

指数为“超过64”符号;也就是说,7位字段显示的数字比实际指数大64。尾数总是大于或等于1/16且小于1的正分数。对于8字节实数,尾数位于第8到63位。二进制尾数的小数点位于位左侧8.位8表示值1/2,位9表示1/4,依此类推。

我尝试过类似于我在python或Perl中看到的东西,但是每种语言都有swift没有的功能,而且类型转换也很混乱。

这是我尝试的一种基于Perl的方法。似乎没有得到正确的价值。按位数学对我来说是新的。

       var sgn = 1.0
        let andSgn = 0x8000000000000000 & bytes8_test
        if( andSgn > 0) { sgn = -1.0 }

       // var sgn = -1 if 0x8000000000000000 & num else 1
        let manta = bytes8_test & 0x00ffffffffffffff
        let exp = (bytes8_test >> 56) & 0x7f
        let powBase = sgn * Double(manta)
        let expPow = (4.0 * (Double(exp) - 64.0) - 56.0)
        var testReal = pow( powBase , expPow )

另一个我试过:

let bitArrayDecode = decodeBitArray(bitArray: bitArray)
        let valueArray = calcValueOfArray(bitArray: bitArrayDecode)
        var exponent:Int16
        //calculate exponent
        if(negative){
            exponent = valueArray - 192
        } else {
            exponent = valueArray - 64
        }
        //calculate mantessa
        var mantissa = 0.0
        //sgn = -1 if 0x8000000000000000 & num else 1
        //mant = num & 0x00ffffffffffffff
        //exp = (num >> 56) & 0x7f
        //return math.ldexp(sgn * mant, 4 * (exp - 64) - 56)

        for index in 0...7 {
            //let mantaByte = bytes8_1st[index]
            //mantissa +=  Double(mantaByte) / pow(256.0, Double(index))
            let bit = pow(2.0, Double(7-index))
            let scaleBit = pow(2.0, Double( index ))
            var mantab = (8.0 * Double( bytes8_1st[1] & UInt8(bit)))/(bit*scaleBit)
            mantissa = mantissa + mantab
            mantab = (8.0 * Double( bytes8_1st[2] & UInt8(bit)))/(256.0 * bit * scaleBit)
            mantissa = mantissa + mantab
            mantab = (8.0 * Double( bytes8_1st[3] & UInt8(bit)))/(256.0 * bit * scaleBit)
            mantissa = mantissa + mantab

        }
        let real = mantissa * pow(16.0, Double(exponent))

更新:

以下部分似乎适用于指数。我正在使用的数据集返回-9。这是我的期望。

        var exp = Int16((bytes8 >> 56) & 0x7f)
        exp = exp - 65 //change from excess 64
        print(exp)

        var sgnVal = 0x8000000000000000 & bytes8
        var sgn = 1.0
        if(sgnVal == 1){
            sgn = -1.0
        }

对于尾数虽然我无法得到正确的计算方法。

数据集:3d 68 db 8b ac 71 0c b4 38 6d f3 7f 67 5e f6 ec

我认为它应该为指数和0.0001返回1e-9

我最接近真正的双倍0.0000000000034907316148746757

     var bytes7 = Array<UInt8>()
        for (index, by) in data.enumerated(){
            if(index < 4) {
             bytes7.append(by[0])
             bytes7.append(by[1])
            }
        }
        for index in 0...7 {
            mantissa += Double(bytes7[index]) / (pow(256.0, Double(index) + 1.0 ))
        }
        var real =  mantissa * pow(16.0, Double(exp));
        print(mantissa)

更新结束。

也似乎没有产生正确的值。这个基于C文件。

如果有人可以帮我解释规范的含义,或者有什么指示,我会非常感激。

谢谢!

swift converters
1个回答
1
投票

根据文档,此代码将8字节的Real数据作为Double返回。

extension Data {
    func readUInt64BE(_ offset: Int) -> UInt64 {
        var value: UInt64 = 0
        _ = Swift.withUnsafeMutableBytes(of: &value) {bytes in
            copyBytes(to: bytes, from: offset..<offset+8)
        }
        return value.bigEndian
    }
    func readReal64(_ offset: Int) -> Double {
        let bitPattern = readUInt64BE(offset)
        let sign: FloatingPointSign = (bitPattern & 0x80000000_00000000) != 0 ? .minus: .plus
        let exponent = (Int((bitPattern >> 56) & 0x00000000_0000007F)-64) * 4 - 56
        let significand = Double(bitPattern & 0x00FFFFFF_FFFFFFFF)
        let result = Double(sign: sign, exponent: exponent, significand: significand)
        return result
    }
}

用法:

//Two 8-byte Real data taken from the example in the doc
let data = Data([
    //1.0000000000000E-03
    0x3e, 0x41, 0x89, 0x37, 0x4b, 0xc6, 0xa7, 0xef,
    //1.0000000000000E-09
    0x39, 0x44, 0xb8, 0x2f, 0xa0, 0x9b, 0x5a, 0x54,
])
let real1 = data.readReal64(0)
let real2 = data.readReal64(8)
print(real1, real2) //->0.001 1e-09

“UPDATE”的另一个例子:

//0.0001 in "UPDATE"
let data = Data([0x3d, 0x68, 0xdb, 0x8b, 0xac, 0x71, 0x0c, 0xb4, 0x38, 0x6d, 0xf3, 0x7f, 0x67, 0x5e, 0xf6, 0xec])
let real = data.readReal64(0)
print(real) //->0.0001

请记住,Double只有52位有效数字(尾数),因此该代码在原始的8字节Real中丢失了一些有效位。我不确定这可能是一个问题。

© www.soinside.com 2019 - 2024. All rights reserved.