将数据转换为双精度(double)会给我错误的值。

huangapple go评论61阅读模式
英文:

Swift Converting Data to double give me wrong value

问题

I have a Data with a list of bytes:
[64, 69, 207, 65, 61, 225, 199, 151]
hex string is equals: 4045cf413de1c797
I'm getting bytes with this function:
var bytes: [UInt64] = data.map { UInt64(bitPattern: Int64($0)) }
data is a Data type

when i convert it to a double i'm getting wrong value
I tried several function to convert it:

Example 1:

extension Data {
enum Endianess {
case little
case big
}

func toFloat(endianess: Endianess = .little) -> Float? {
guard self.count <= 4 else { return nil }

switch endianess {
case .big:
let data = [UInt8](repeating: 0x00, count: 4-self.count) + self
return data.withUnsafeBytes { $0.load(as: Float.self) }
case .little:
let data = self + [UInt8](repeating: 0x00, count: 4-self.count)
return data.reversed().withUnsafeBytes { $0.load(as: Float.self) }
}
}
}
This one gives me Nil

Example 2:

var f: Float = 0.0
memcpy(&f, bytes, 4)

The result: 8.96831017167883e-44

Example 3:

let floatNb: Float = dataSliced.reversed().withUnsafeBytes { $0.load(as:
Float.self)
}

The result: 0.11024397

without reversed() i'm getting error:
Fatal error: load from misaligned raw pointer

Example 4:

extension Numeric {
init<D: DataProtocol>(_ data: D) {
var value: Self = .zero
let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
//assert(size == MemoryLayout.size(ofValue: value))
self = value
}
}
Result is: -4.089067083288947e-194

The good result is: 43.61917851948163

How can i convert properly a Data to double?

Any help will be appreciated

英文:

I have a Data with a list of bytes :
[64, 69, 207, 65, 61, 225, 199, 151]
hex string is equals : 4045cf413de1c797
I'm getting bytes with this function :
var bytes: [UInt64] = data.map { UInt64(bitPattern: Int64($0)) }
data is a Data type

when i convert it to a double i'm getting wrong value
I tried several function to convert it :

Example 1 :

 extension Data {
 enum Endianess {
    case little
    case big
}

func toFloat(endianess: Endianess = .little) -&gt; Float? {
    guard self.count &lt;= 4 else { return nil }

    switch endianess {
    case .big:
        let data = [UInt8](repeating: 0x00, count: 4-self.count) + self
        return data.withUnsafeBytes { $0.load(as: Float.self) }
    case .little:
        let data = self + [UInt8](repeating: 0x00, count: 4-self.count)
        return data.reversed().withUnsafeBytes { $0.load(as: Float.self) }
    }
    }
    }

This one gives me Nil

Example 2 :

        var f:Float = 0.0
        memcpy(&amp;f, bytes, 4)

The result : 8.96831017167883e-44

Example 3:

       let floatNb:Float = dataSliced.reversed().withUnsafeBytes { $0.load(as: 
       Float.self) 
       }

The result : 0.11024397

without reversed() i'm getting error :
Fatal error: load from misaligned raw pointer

Example 4 :

  extension Numeric {
   init&lt;D: DataProtocol&gt;(_ data: D) {
    var value: Self = .zero
    let size = withUnsafeMutableBytes(of: &amp;value, { data.copyBytes(to: $0)} )
    //assert(size == MemoryLayout.size(ofValue: value))
    self = value
  }
  }

Result is : -4.089067083288947e-194

The good result is : 43.61917851948163

How can i convert properly a Data to double ?

Any help will be appreciated

答案1

得分: 1

你的问题是,目标类型使用了 Float 而不是 DoubleFloat 只使用前 4 个字节。

let bytes = [UInt8](arrayLiteral: 64, 69, 207, 65, 61, 225, 199, 151)

let result = bytes.reversed().withUnsafeBytes {
    $0.load(
        as: Double.self
    )
}

assert(43.61917851948163 == result, "无效的结果 \(result)")
英文:

Your problem that as destination you are using Float instead of Double. Float is using only first 4 bytes.

let bytes = [UInt8](arrayLiteral: 64, 69, 207, 65, 61, 225, 199, 151)

let result = bytes.reversed().withUnsafeBytes {
    $0.load(
        as:Double.self
    )
}

assert(43.61917851948163 == result, &quot;invalid result \(result)&quot;)

答案2

得分: 0

Here is the translated code:

最终,我通过这样分离 Int  Double 来使它工作了:
对于 Double

let bytes: [UInt16] = dataSliced.map { UInt16(bitPattern: Int16($0)) }
dump(bytes)
if(bytes.count == 8){
    var hexValue = dataSliced.toHex()
    hexValue = "0x\(hexValue)"
    let scanner = Scanner(string: hexValue)
    
    var decimalValue: UInt64 = 0
    scanner.scanHexInt64(&decimalValue)
    
    doubleValue = Double(bitPattern: decimalValue)
    print("doubleValue \(doubleValue)")
}

对于 Int

let decimalValue = dataSliced.reduce(0) { value, byte in
    return value << 8 | Int(byte)
}
return decimalValue

Please note that the code has been translated as requested, and I have removed any non-code content.

英文:

I finally get this worked by separating Int and Double like this :
For double :

   let bytes: [UInt16] = dataSliced.map { UInt16(bitPattern: Int16($0)) }
    dump(bytes)
    if(bytes.count == 8){
        var hexValue = dataSliced.toHex()
        hexValue = &quot;0x\(hexValue)&quot;
        let scanner = Scanner(string: hexValue)
        
        var decimalValue: UInt64 = 0
        scanner.scanHexInt64(&amp;decimalValue)
        
        doubleValue = Double(bitPattern: decimalValue)
        print(&quot;doubleValue \(doubleValue)&quot;)

For Int

    let decimalValue = dataSliced.reduce(0) { value, byte in
        return value &lt;&lt; 8 | Int(byte)
    }
    return decimalValue

huangapple
  • 本文由 发表于 2023年5月25日 20:40:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76332377.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定