How to convert 4 bytes to a Swift float?
Drop the &
on &bytes
. bytes
is an array.
var bytes:Array<UInt8> = [0x9A, 0x99, 0x99, 0x41] //19.20000
var f:Float = 0.0
memccpy(&f, bytes, 4, 4) // as per OP. memcpy(&f, bytes, 4) preferred
println ("f=\(f)")// f=19.2000007629395
Update Swift 3
memccpy
does not seem to work in Swift 3. As commentators have said, use memcpy
:
import Foundation
var bytes:Array<UInt8> = [0x9A, 0x99, 0x99, 0x41] //19.20000
var f:Float = 0.0
/* Not in Swift 3
memccpy(&f, bytes, 4, 4) // as per OP.
print("f=\(f)")// f=19.2
*/
memcpy(&f, bytes, 4) /
print("f=\(f)")// f=19.2
How to convert bytes to a float value in swift?
<44fa0000>
is the big-endian memory representation of the
binary floating point number 2000.0
. To get the number back from
the data, you have to read it into an UInt32
first, convert from
big-endian to host byteorder, and then cast the result to
a Float
.
In Swift 2 that would be
func floatValueFromData(data: NSData) -> Float {
return unsafeBitCast(UInt32(bigEndian: UnsafePointer(data.bytes).memory), Float.self)
}
Example:
let bytes: [UInt8] = [0x44, 0xFA, 0x00, 0x00]
let data = NSData(bytes: bytes, length: 4)
print(data) // <44fa0000>
let f = floatValueFromData(data)
print(f) // 2000.0
In Swift 3 you would use Data
instead of NSData
, and theunsafeBitCast
can be replaced by the Float(bitPattern:)
initializer:
func floatValue(data: Data) -> Float {
return Float(bitPattern: UInt32(bigEndian: data.withUnsafeBytes { $0.pointee } ))
}
In Swift 5 the withUnsafeBytes()
method of Data
calls the closure with an (untyped) UnsafeRawBufferPointer
, and you can load()
the value from the raw memory:
func floatValue(data: Data) -> Float {
return Float(bitPattern: UInt32(bigEndian: data.withUnsafeBytes { $0.load(as: UInt32.self) }))
}
4 bytes to a Float in a swift gives an unexpectedly small result
You are on a little-endian platform, so your array is equivalent to the 32-bit integer 0x00000019
, which, as an IEEE single precision floating-point number, is approximately 3.5 * 10-44.
Swift: How to convert Bytes into a float / get a more precise number?
The problem is that you're trying to turn little endian UInt32
values into Float
merely by "reinterpreting" the same bit patterns as a new value (that's what Float(bitPattern:)
is for), but that's not at all how Float stores its data. Swift's Float
and Double
datatypes are implementations of the 32 and 64 bit floating point data types from IEEE 754. There's plenty of online resources that explain it, but the TL;DR is that they store numbers in a similar way as scientific notation, with a mantissa raised to the power of an exponent.
I think part of your difficulty comes from trying to do too much at once. Break it down into small pieces. Write a function that takes your data, and decomposes it into the 3 UInt32
components. Then write a separate function that does whatever transformation you want on those components, such as turning them into floats. Here's a rough example:
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)
How to convert a float value to byte array in swift?
Float
to NSData
:
var float1 : Float = 40.0
let data = NSData(bytes: &float1, length: sizeofValue(float1))
print(data) // <00002042>
... and back to Float
:
var float2 : Float = 0
data.getBytes(&float2, length: sizeofValue(float2))
print(float2) // 40.0
(The same would work for other "simple" types like Double
,Int
, ...)
Update for Swift 3, using the new Data
type:
var float1 : Float = 40.0
let data = Data(buffer: UnsafeBufferPointer(start: &float1, count: 1))
print(data as NSData) // <00002042>
let float2 = data.withUnsafeBytes { $0.pointee } as Float
print(float2) // 40.0
(See also round trip Swift number types to/from Data)
Update for Swift 4 and later:
var float1 : Float = 40.0
let data = Data(buffer: UnsafeBufferPointer(start: &float1, count: 1))
let float2 = data.withUnsafeBytes { $0.load(as: Float.self) }
print(float2) // 40.0
Remark: load(as:)
requires the data to be properly aligned, for Float
that would be on a 4 byte boundary. See e.g. round trip Swift number types to/from Data for other solutions which work for arbitrarily aligned data.
Properly reading 4 bytes in -Hex- NSData form into its proper data type (float or int) in Swift
After a while of research and community polling, I have found the answer from one of the community members at: http://forum.rfduino.com/index.php?topic=727.15#msg3393 So credit goes to him.
The code that properly translates the data into a UInt32 and then into a float is this:
var test:UInt32 = 0
data.getBytes(&test, length: sizeof(NSInteger))
var floatVal:Float = unsafeBitCast(reversed, Float.self)
println(floatVal)
Assuming you have your 'data' variable as an NSData.
However if you have a similar problem but you need to flip the bytes before converting them into floats the code changes to this:
var test:UInt32 = 0
data.getBytes(&test, length: sizeof(NSInteger))
var reversed = test.byteSwapped
var floatVal:Float = unsafeBitCast(reversed, Float.self)
println(floatVal)
This solution accounts for both Endianness. Big thanks to Bill for providing this solution
An even smaller/better solution would be:
var floatVal:Float = 0.0;
data.getBytes(&floatVal, length:sizeof(Float))
println(floatVal)
This one would does not flip bits tho, so if it doesn't need to swap bytes then this would be the safer/better route.
How to convert a pair of bytes into a Float using Swift
Your issue there is that you are not suppose to initialize your Float using the bitPattern initializer and/or use the UInt32(littleEndian:) initializer. What you need is to convert those 2 bytes to Int16, coerce it to Float and then multiply by the factor of 9.81/2048 to get its acceleration.
Expanding on that, you can create a Numeric initializer that takes an object that conforms to DataProtocol (Data or Bytes [UInt8]):
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
}
}
Then you can initialize your Int16 object with the subdata (two bytes).
let bytes: [UInt8] = [3, 4, 250, 255, 199, 249, 91, 191]
let xData = bytes[2..<4]
let yData = bytes[4..<6]
let zData = bytes[6..<8]
let factor: Float = 9.81/2048
let xAxis = Float(Int16(xData)) * factor
let yAxis = Float(Int16(yData)) * factor
let zAxis = Float(Int16(zData)) * factor
print("x:", xAxis, "y:", yAxis, "z:", zAxis) // x: -0.028740235 y: -7.6305327 z: -79.27036
How to convert an ContiguousArray of Floats into a byte array in Swift?
You can use the withUnsafeBytes()
method to get a buffer pointer to the underlying bytes of the array's contiguous storage, and directly initialize an [UInt8]
array from that buffer pointer. Example:
let floatArray: [Float] = [1.0, 2.0]
// Works also with a ContiguousArray:
// let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let byteArray = floatArray.withUnsafeBytes { Array($0) }
print(byteArray) // [0, 0, 128, 63, 0, 0, 0, 64]
Equivalently (based on Leo's suggestion):
let byteArray = floatArray.withUnsafeBytes(Array.init)
The byte array contains the binary representation of the floating point numbers in host byte order (which is little-endian on all current Apple platforms). A conversion to big-endian is possible, but not without an intermediate copy to an integer array:
let floatArray: ContiguousArray<Float> = [1.0, 2.0]
let intArray = floatArray.map { $0.bitPattern.bigEndian }
let byteArray = intArray.withUnsafeBytes(Array.init)
print(byteArray) // 63, 128, 0, 0, 64, 0, 0, 0]
Reverse conversion: A simple method would be
let floatArray2 = byteArray.withUnsafeBytes { Array($0.bindMemory(to: Float.self)) }
print(floatArray2) // [1.0, 2.0]
However, that requires that the element storage of the byte array is properly aligned for floating point numbers. If that is not guaranteed then you can do
var floatArray2 = [Float](repeating: 0.0, count: byteArray.count / MemoryLayout<Float>.stride)
_ = floatArray2.withUnsafeMutableBytes { byteArray.copyBytes(to: $0) }
print(floatArray2) // [1.0, 2.0]
Related Topics
How to Trigger Xcode's 'Update to Latest Package Versions' from Command Line
How to Change Text Color of Actionsheet in Swiftui
Custom Mkannotation Not Moving When Coordinate Set
Uitableviewautomaticdimension Not Working on iOS 8
Metal Kernels Not Behaving Properly on the New MACbook Pro (Late 2016) Gpus
How to Set Avaudioengine Input and Output Devices (Swift/Macos)
Swiftui Sheet Gets Dismissed the First Time It Is Presented
Are Built-In Intrinsic Functions Available in Swift 3
Maccatalyst App: How to Close a Window Without Terminating The App
Unresponsive Uibutton in Subview Added to Uistackview
Unwrapping Optional in Swiftui View
Swift Compiler Error Int Is Not Convertible to Cgfloat
Textfield in Swiftui Loses Focus When I Enter a Character
Rotate a Text View and Its Frame in Swiftui
Swift Cannot Assign to Self in a Class Init Method
Swiftui Classes That Conforms Observableobject Should Be Singleton