Swift:如何将Bytes转换为float /获得更精确的数字?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift:如何将Bytes转换为float /获得更精确的数字?相关的知识,希望对你有一定的参考价值。

我以6字节的形式从BLE设备获取加速度计数据,我想将其转换为浮点值,以尽可能精确。

每2个字节代表一个不同的轴,(分别为x,y和z)。而不是像982这样的数字,我想要一个像0.98243873这样的数字

我尝试通过尝试将字节转换为Float ...

let data = characteristic.value!

let floatX = Float(bitPattern:UInt32(littleEndian:data[0...1].withUnsafeBytes$0.pointee))

OR

let floatX = data[0...1].withUnsafeBytes$0.pointee as Float

但是当Int16值为-6.777109e-21并且我期待像1047之类的东西时,我得到像1.04793283这样奇怪的数字。它会与正在签名的字节有关吗?我可以从两个字节获得这样的精度吗?

答案

问题是你试图将小端UInt32值转换为Float只是通过“重新解释”相同的位模式作为新值(这就是Float(bitPattern:)的用途),但这根本不是Float如何存储其数据。 Swift的FloatDouble数据类型是来自IEEE 754的32位和64位浮点数据类型的实现。有很多在线资源可以解释它,但是TL; DR是他们以类似于科学记数法的方式存储数字,尾数被提升到指数的幂。

我认为你的一部分困难来自于试图立刻做太多。把它分解成小块。编写一个获取数据的函数,并将其分解为3个UInt32组件。然后编写一个单独的函数,对这些组件执行任何转换,例如将它们转换为浮点数。这是一个粗略的例子:

import Foundation

func createTestData(x: UInt32, y: UInt32, z: UInt32) -> Data 
    return [x, y, z]
        .map  UInt32(littleEndian: $0) 
        .withUnsafeBufferPointer  Data(buffer: $0) 


func decode(data: Data) -> (x: UInt32, y: UInt32, z: UInt32) 
    let values = data.withUnsafeBytes  bufferPointer in
            bufferPointer
                .bindMemory(to: UInt32.self)
                .map  rawBitPattern in
                    return UInt32(littleEndian: rawBitPattern)
                
        

    assert(values.count == 3)
    return (x: values[0], y: values[1], z: values[2])


func transform(ints: (x: UInt32, y: UInt32, z: UInt32))
    -> (x: Float, y: Float, z: Float) 
    let transform: (UInt32) -> Float =  Float($0) / 1000  // define whatever transformation you need
    return (transform(ints.x), transform(ints.y), transform(ints.z))


let testData = createTestData(x: 123, y: 456, z: 789)
print(testData) // => 12 bytes
let decodedVector = decode(data: testData)
print(decodedVector) // => (x: 123, y: 456, z: 789)
let intsToFloats = transform(ints: decodedVector)
print(intsToFloats) // => (x: 0.123, y: 0.456, z: 0.789)
另一答案

如果你收到6个字节,其中每个2个字节代表一个轴,你实际上每个接收3个数字,16位整数。要把它们变成你想要的那种漂浮物(1047 - > 1.047xxx),你必须明显将它们分别用1000.0

我不知道Swift,但只是做了类似这样的伪代码:

x = (first_byte + 256 * second_byte) / 1000.0;  // or vice versa, if big-endian
y = (third_byte + 256 * fourth_byte) / 1000.0;  // same...
z = (fifth_byte + 256 * sixth_byte) / 1000.0;   // same again

正如我所指出的,如果设备出来的字节是big-endian,你显然会:

x = (256 * first_byte + second_byte) / 1000.0; 
// etc...

你也许可以通过乘以反向来加速这一点,即* 0.001,因为乘法通常比除法快一点。但是,有些编译器会为你做这件事,如果他们注意到这是一个常数:

x = (...) * 0.001;

以上是关于Swift:如何将Bytes转换为float /获得更精确的数字?的主要内容,如果未能解决你的问题,请参考以下文章

在Swift中将bytes / UInt8数组转换为Int

如何将 byte[] 转换为 float[] 并返回 Java?

如何在 Swift 中将 Floats 的 ContiguousArray 转换为字节数组?

Swift 4 Codable:将 JSON 返回字符串转换为 Int/Date/Float

在 swift 中将 String 类型数组转换为 Float 类型数组 不能将类型 'String' 的值分配给类型 'Double' 的下标。

JavaScript - 以干净的方式将字节转换为float