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) }))
}
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 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 bytes to half-floats in Swift?
There is no 16-bit floating point type in Swift, but you can convert
the results to 32-bit floating point numbers (Float
).
This thread
- 32-bit to 16-bit Floating Point Conversion
contains a lot of information about the
Half-precision floating-point format, and various conversion methods. The crucial hint however is in Ian Ollman's answer:
On OS X / iOS, you can use
vImageConvert_PlanarFtoPlanar16F
andvImageConvert_Planar16FtoPlanarF
. See Accelerate.framework.
Ian did provide no code however, so here is a possible implementation
in Swift:
func areaHistogram(image : UIImage) {
let inputImage = CIImage(image: image)
let totalBytes : Int = bpp * BINS //8 * 64 for example
let bitmap = calloc(1, totalBytes)
let filter = CIFilter(name: "CIAreaHistogram")!
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(CIVector(x: 0, y: 0, z: image.size.width, w: image.size.height), forKey: kCIInputExtentKey)
filter.setValue(BINS, forKey: "inputCount")
filter.setValue(1, forKey: "inputScale")
let myEAGLContext = EAGLContext(API: .OpenGLES2)
let options = [kCIContextWorkingColorSpace : kCFNull]
let context : CIContext = CIContext(EAGLContext: myEAGLContext, options: options)
context.render(filter.outputImage!, toBitmap: bitmap, rowBytes: totalBytes, bounds: filter.outputImage!.extent, format: kCIFormatRGBAh, colorSpace: CGColorSpaceCreateDeviceRGB())
// *** CONVERSION FROM 16-bit TO 32-bit FLOAT ARRAY STARTS HERE ***
let comps = 4 // Number of components (RGBA)
// Array for the RGBA values of the histogram:
var rgbaFloat = [Float](count: comps * BINS, repeatedValue: 0)
// Source and image buffer structure for vImage conversion function:
var srcBuffer = vImage_Buffer(data: bitmap, height: 1, width: UInt(comps * BINS), rowBytes: bpp * BINS)
var dstBuffer = vImage_Buffer(data: &rgbaFloat, height: 1, width: UInt(comps * BINS), rowBytes: comps * sizeof(Float) * BINS)
// Half-precision float to Float conversion of entire buffer:
if vImageConvert_Planar16FtoPlanarF(&srcBuffer, &dstBuffer, 0) == kvImageNoError {
for bin in 0 ..< BINS {
let R = rgbaFloat[comps * bin + 0]
let G = rgbaFloat[comps * bin + 1]
let B = rgbaFloat[comps * bin + 2]
print("R/G/B = \(R) \(G) \(B)")
}
}
free(bitmap)
}
Remarks:
- You need to
import Accelerate
. - Note that your code allocates
totalBytes * bpp
bytes instead
of the necessarytotalBytes
. - The
kCIFormatRGBAh
pixel format is not supported on the Simulator (as of Xcode 7), so you have to test the code on a real device.
Update: Swift 5.3 (Xcode 12, currently in beta) introduces a new Float16
type which is available in iOS 14, see SE-0277 Float16 on Swift Evolution.
This simplifies the code because a conversion to Float
is no longer necessary. I have also removed the use of OpenGL functions which are deprecated as of iOS 12:
func areaHistogram(image: UIImage, bins: Int) -> [Float16] {
let comps = 4 // Number of components (RGBA)
let inputImage = CIImage(image: image)
var rgbaFloat = [Float16](repeating: 0, count: comps * bins)
let totalBytes = MemoryLayout<Float16>.size * comps * bins
let filter = CIFilter(name: "CIAreaHistogram")!
filter.setValue(inputImage, forKey: kCIInputImageKey)
filter.setValue(CIVector(x: 0, y: 0, z: image.size.width, w: image.size.height), forKey: kCIInputExtentKey)
filter.setValue(bins, forKey: "inputCount")
filter.setValue(1, forKey: "inputScale")
let options: [CIContextOption : Any] = [.workingColorSpace : NSNull()]
let context = CIContext(options: options)
rgbaFloat.withUnsafeMutableBytes {
context.render(filter.outputImage!, toBitmap: $0.baseAddress!, rowBytes: totalBytes,
bounds: filter.outputImage!.extent, format: CIFormat.RGBAh,
colorSpace: CGColorSpaceCreateDeviceRGB())
}
return rgbaFloat
}
Get raw bytes of a float in Swift
Update for Swift 3: As of Swift 3, all floating point types
have bitPattern
property which returns an unsigned integer with
the same memory representation, and a corresponding init(bitPattern:)
constructor for the opposite conversion.
Example: Float
to UInt32
:
let x = Float(1.5)
let bytes1 = x.bitPattern
print(String(format: "%#08x", bytes1)) // 0x3fc00000
Example: UInt32
to Float
:
let bytes2 = UInt32(0x3fc00000)
let y = Float(bitPattern: bytes2)
print(y) // 1.5
In the same way you can convert between Double
and UInt64
,
or between CGFloat
and UInt
.
Old answer for Swift 1.2 and Swift 2: The Swift floating point types have a _toBitPattern()
method:
let x = Float(1.5)
let bytes1 = x._toBitPattern()
print(String(format: "%#08x", bytes1)) // 0x3fc00000
let bytes2: UInt32 = 0b00111111110000000000000000000000
print(String(format: "%#08x", bytes2)) // 0x3fc00000
print(bytes1 == bytes2) // true
This method is part of the FloatingPointType
protocol
to which Float
, Double
and CGFloat
conform:
/// A set of common requirements for Swift's floating point types.
protocol FloatingPointType : Strideable {
typealias _BitsType
static func _fromBitPattern(bits: _BitsType) -> Self
func _toBitPattern() -> _BitsType
// ...
}
(As of Swift 2, these definition are not visible anymore in the
API documentation, but they still exist and work as before.)
The actual definition of _BitsType
is not visible in the API
documentation, but it is UInt32
for Float
, UInt64
forDouble
, and Int
for CGFloat
:
print(Float(1.0)._toBitPattern().dynamicType)
// Swift.UInt32
print(Double(1.0)._toBitPattern().dynamicType)
// Swift.UInt64
print(CGFloat(1.0)._toBitPattern().dynamicType)
// Swift.UInt
_fromBitPattern()
can be used for the conversion into the other
direction:
let y = Float._fromBitPattern(0x3fc00000)
print(y) // 1.5
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.
round trip Swift number types to/from Data
Note: The code has been updated for Swift 5 (Xcode 10.2) now. (Swift 3 and Swift 4.2 versions can be found in the edit history.) Also possibly unaligned data is now correctly handled.
How to create Data
from a value
As of Swift 4.2, data can be created from a value simply with
let value = 42.13
let data = withUnsafeBytes(of: value) { Data($0) }
print(data as NSData) // <713d0ad7 a3104540>
Explanation:
withUnsafeBytes(of: value)
invokes the closure with a buffer pointer covering the raw bytes of the value.- A raw buffer pointer is a sequence of bytes, therefore
Data($0)
can be used to create the data.
How to retrieve a value from Data
As of Swift 5, the withUnsafeBytes(_:)
of Data
invokes the closure with an “untyped” UnsafeMutableRawBufferPointer
to the bytes. The load(fromByteOffset:as:)
method the reads the value from the memory:
let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
let value = data.withUnsafeBytes {
$0.load(as: Double.self)
}
print(value) // 42.13
There is one problem with this approach: It requires that the memory is property aligned for the type (here: aligned to a 8-byte address). But that is not guaranteed, e.g. if the data was obtained as a slice of another Data
value.
It is therefore safer to copy the bytes to the value:
let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
var value = 0.0
let bytesCopied = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
assert(bytesCopied == MemoryLayout.size(ofValue: value))
print(value) // 42.13
Explanation:
withUnsafeMutableBytes(of:_:)
invokes the closure with a mutable buffer pointer covering the raw bytes of the value.- The
copyBytes(to:)
method ofDataProtocol
(to whichData
conforms) copies bytes from the data to that buffer.
The return value of copyBytes()
is the number of bytes copied. It is equal to the size of the destination buffer, or less if the data does not contain enough bytes.
Generic solution #1
The above conversions can now easily be implemented as generic methods of struct Data
:
extension Data {
init<T>(from value: T) {
self = Swift.withUnsafeBytes(of: value) { Data($0) }
}
func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
var value: T = 0
guard count >= MemoryLayout.size(ofValue: value) else { return nil }
_ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: $0)} )
return value
}
}
The constraint T: ExpressibleByIntegerLiteral
is added here so that we can easily initialize the value to “zero” – that is not really a restriction because this method can be used with “trival” (integer and floating point) types anyway, see below.
Example:
let value = 42.13 // implicit Double
let data = Data(from: value)
print(data as NSData) // <713d0ad7 a3104540>
if let roundtrip = data.to(type: Double.self) {
print(roundtrip) // 42.13
} else {
print("not enough data")
}
Similarly, you can convert arrays to Data
and back:
extension Data {
init<T>(fromArray values: [T]) {
self = values.withUnsafeBytes { Data($0) }
}
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
_ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
return array
}
}
Example:
let value: [Int16] = [1, Int16.max, Int16.min]
let data = Data(fromArray: value)
print(data as NSData) // <0100ff7f 0080>
let roundtrip = data.toArray(type: Int16.self)
print(roundtrip) // [1, 32767, -32768]
Generic solution #2
The above approach has one disadvantage: It actually works only with "trivial"
types like integers and floating point types. "Complex" types like Array
and String
have (hidden) pointers to the underlying storage and cannot be
passed around by just copying the struct itself. It also would not work with
reference types which are just pointers to the real object storage.
So solve that problem, one can
Define a protocol which defines the methods for converting to
Data
and back:protocol DataConvertible {
init?(data: Data)
var data: Data { get }
}Implement the conversions as default methods in a protocol extension:
extension DataConvertible where Self: ExpressibleByIntegerLiteral{
init?(data: Data) {
var value: Self = 0
guard data.count == MemoryLayout.size(ofValue: value) else { return nil }
_ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
self = value
}
var data: Data {
return withUnsafeBytes(of: self) { Data($0) }
}
}I have chosen a failable initializer here which checks that the number of bytes provided
matches the size of the type.And finally declare conformance to all types which can safely be converted to
Data
and back:extension Int : DataConvertible { }
extension Float : DataConvertible { }
extension Double : DataConvertible { }
// add more types here ...
This makes the conversion even more elegant:
let value = 42.13
let data = value.data
print(data as NSData) // <713d0ad7 a3104540>
if let roundtrip = Double(data: data) {
print(roundtrip) // 42.13
}
The advantage of the second approach is that you cannot inadvertently do unsafe conversions. The disadvantage is that you have to list all "safe" types explicitly.
You could also implement the protocol for other types which require a non-trivial conversion, such as:
extension String: DataConvertible {
init?(data: Data) {
self.init(data: data, encoding: .utf8)
}
var data: Data {
// Note: a conversion to UTF-8 cannot fail.
return Data(self.utf8)
}
}
or implement the conversion methods in your own types to do whatever is
necessary so serialize and deserialize a value.
Byte order
No byte order conversion is done in the above methods, the data is always in
the host byte order. For a platform independent representation (e.g.
“big endian” aka “network” byte order), use the corresponding integer
properties resp. initializers. For example:
let value = 1000
let data = value.bigEndian.data
print(data as NSData) // <00000000 000003e8>
if let roundtrip = Int(data: data) {
print(Int(bigEndian: roundtrip)) // 1000
}
Of course this conversion can also be done generally, in the generic
conversion method.
How to convert a double into a byte array in swift?
typealias Byte = UInt8
func toByteArray<T>(var value: T) -> [Byte] {
return withUnsafePointer(&value) {
Array(UnsafeBufferPointer(start: UnsafePointer<Byte>($0), count: sizeof(T)))
}
}
toByteArray(1729.1729)
toByteArray(1729.1729 as Float)
toByteArray(1729)
toByteArray(-1729)
But the results are reversed from your expectations (because of endianness):
[234, 149, 178, 12, 177, 4, 155, 64]
[136, 37, 216, 68]
[193, 6, 0, 0, 0, 0, 0, 0]
[63, 249, 255, 255, 255, 255, 255, 255]
Added:
func fromByteArray<T>(value: [Byte], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}
let a: Double = 1729.1729
let b = toByteArray(a) // -> [234, 149, 178, 12, 177, 4, 155, 64]
let c = fromByteArray(b, Double.self) // -> 1729.1729
For Xcode8/Swift3.0:
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
}
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
For Xcode8.1/Swift3.0.1
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafeBytes(of: &value) { Array($0) }
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBytes {
$0.baseAddress!.load(as: T.self)
}
}
How in swift to convert Int16 to two UInt8 Bytes
You should work with unsigned integers:
let bytes: [UInt8] = [255, 251]
let uInt16Value = UInt16(bytes[0]) << 8 | UInt16(bytes[1])
let uInt8Value0 = uInt16Value >> 8
let uInt8Value1 = UInt8(uInt16Value & 0x00ff)
If you want to convert UInt16 to bit equivalent Int16 then you can do it with specific initializer:
let int16Value: Int16 = -15
let uInt16Value = UInt16(bitPattern: int16Value)
And vice versa:
let uInt16Value: UInt16 = 65000
let int16Value = Int16(bitPattern: uInt16Value)
In your case:
let nv: Int16 = -15
let uNv = UInt16(bitPattern: nv)
UInt8(uNv >> 8)
UInt8(uNv & 0x00ff)
Related Topics
Preparing for Swift 4 - Unsafemutablepointer Migration to Unsafemutablebufferpointer
Retrieve Data from an Unknown Child Name with Firebase and Swift
Get Out of Navigation Controller and Go Back to Tab Bar View
Arkit: Plot a Node at a Specific Pixel at a Specific Z Distance from Camera
Alamofire Encodes Image in Which Format
Can't Hide Status Bar in Avplayerviewcontroller's Portrait Mode
Expose an Interface of a Class Loaded from a Framework at Runtime
Loading Many UIimages from Disk Blocks Main Thread
How to Get User Nearby My Location in Geofire,Firebase
Error: Missing Return in a Closure Expected to Return 'Uiviewcontroller' (Xcode, Swift, iOS 13)
Swift & Nstextfield: How to Work with Text Completion
Osx/Swift: Call Function at a Specific Date/Time
How Make Polygon Without Intersection in Swift
Swift: How to Get Image Name from Assets
Return Object for a Method Inside Completion Block
Uipageviewcontroller with Previous and Next Buttons
What's a Placeholder? Why Do We Need to Define Placeholder Data Type for Generics