Using vDSP.convertElements with vDSP.RoundingMode - swift

I am trying to round all elements in the vector using new static function convertElements from Accelerate framework.
Sadly i don't know how to use it.
Here is what i tried:
let a: [Double] = [10.6, 20, 30.8, 40, 50, 60, 70, 80, 90, 100]
var b = [Int](repeating: 0, count: a.count)
var round: vDSP.RoundingMode = vDSP.RoundingMode.towardNearestInteger
vDSP.convertElements(of: a, to: &b, rounding: round)
This code throws error:
error: ambiguous reference to static method 'convertElements(of:to:rounding:)'
vDSP.convertElements(of: a, to: &b, rounding: vDSP.RoundingMode.towardNearestInteger)
Any idea how to use this function?
Seems like setting value of vDSP.RoundingMode type is the problem.

You're using the wrong type for the to: array. It needs to be [Int32], not [Int].
Change:
var b = [Int](repeating: 0, count: a.count)
to:
var b = [Int32](repeating: 0, count: a.count)
In the link you provided, the definition of the function is:
static func convertElements<U, V>(of source: U, to destination: inout V,
rounding: vDSP.RoundingMode) where U : AccelerateBuffer,
V : AccelerateMutableBuffer, U.Element == Double, V.Element == Int32
Notice that V.Element is Int32.
As noted by #MartinR in the comments, other types are possible including Int8, UInt8, Int16, UInt16, and UInt32. All of the calls are detailed here.

Related

How to convert a pair of bytes into a Float using Swift

I am using this article to communicate with an IoT sensor via BLE. In the article, this quote is mentioned:
The first two bytes do not seem to belong to the data (probably a prefix to denote that it is a data packet), but the remaining ones are more interesting. For the accelerometer, we get three signed 16 bit integers (little endian), which can simply be scaled to the range we set up to get our setup sequence. So the +/-2^15 range of the signed 16bit integer corresponds to the +/-16g, resulting in a factor 1/2048. To get the acceleration in m/s², we apply a factor of 9.81/2048. So, the corresponding bluetooth part reads:
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="2" length="2">accXRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="4" length="2">accYRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="6" length="2">accZRaw</output>
To read this code, I am running this Swift code:
private func sensor(from characteristic: CBCharacteristic) {
guard let characteristicData = characteristic.value,
let _ = characteristicData.first else { return }
let data = characteristic.value!
var values = [UInt8](repeating: 0, count: data.count)
data.copyBytes(to: &values, count: data.count)
print("values = \(values)")
}
The result once I do a print is:
values = [3, 4, 250, 255, 199, 249, 91, 191]
Alike the article mentions, I can confirm that the first two bytes do not belong to any data, and are consistently repeating. Bytes values[2-7] are constantly changing, which makes me more confident that the pairs represent accXRaw, accYRaw, and accZRaw. What I want to do now is convert the pairs to doubles.
For example:
values[2], values[3] = [250 255] (accXRaw)
values[4], values[5] = [199 249] (accYRaw)
values[6], values[7] = [91 191] (accZRaw)
In the article, the author does this via a int16 little endian. I want to do the same with swift 5, but not sure if I am doing it correctly. Here is my code:
let xAxis = Float(bitPattern: UInt32(littleEndian: [values[2], values[3], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let yAxis = Float(bitPattern: UInt32(littleEndian: [values[4], values[5], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let zAxis = Float(bitPattern: UInt32(littleEndian: [values[6], values[7], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
print("x=\(xAxis), y=\(yAxis), z=\(zAxis)");
The resulting printout is:
values = [3, 4, 250, 255, 199, 249, 91, 191]
x=9.1827e-41, y=8.9603e-41, z=6.8645e-41
These numbers just look weird, and I suspect I am doing something wrong. Am I reading the byte pairs correctly ( at least in line with the article ) ? If not, what mistakes did I make?
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

Convert Int to Array of UInt8 in swift

I want to convert a standard integer in a list of UInt8 in swift.
var x:Int = 2019
2019 can be written (for example) in hexadecimal 7E3 so i want some kind of function that converts is to a list of UInt8s which looks like this.
var y:[Uint8] = [0x07, 0xE3]
I already found this: Convert integer to array of UInt8 units but he/she is convertign the ascii symbols of the number not the number itself. So his example 94887253 should give a list like [0x05, 0xA7, 0xDD, 0x55].
In the best case the function i'm looking for has some kind of usage so that i can also choose the minimum length of the resulting array so that for example
foo(42, length:2) -> [0x00, 0x2A]
or
foo(42, length:4) -> [0x00, 0x00, 0x00, 0x2A]
You could do it this way:
let x: Int = 2019
let length: Int = 2 * MemoryLayout<UInt8>.size //You could specify the desired length
let a = withUnsafeBytes(of: x) { bytes in
Array(bytes.prefix(length))
}
let result = Array(a.reversed()) //[7, 227]
Or more generally, we could use a modified version of this snippet:
func bytes<U: FixedWidthInteger,V: FixedWidthInteger>(
of value : U,
to type : V.Type,
droppingZeros: Bool
) -> [V]{
let sizeInput = MemoryLayout<U>.size
let sizeOutput = MemoryLayout<V>.size
precondition(sizeInput >= sizeOutput, "The input memory size should be greater than the output memory size")
var value = value
let a = withUnsafePointer(to: &value, {
$0.withMemoryRebound(
to: V.self,
capacity: sizeInput,
{
Array(UnsafeBufferPointer(start: $0, count: sizeInput/sizeOutput))
})
})
let lastNonZeroIndex =
(droppingZeros ? a.lastIndex { $0 != 0 } : a.indices.last) ?? a.startIndex
return Array(a[...lastNonZeroIndex].reversed())
}
let x: Int = 2019
bytes(of: x, to: UInt8.self, droppingZeros: true) // [7, 227]
bytes(of: x, to: UInt8.self, droppingZeros: false) // [0, 0, 0, 0, 0, 0, 7, 227]

How to convert Int to byte array of 4 bytes in Swift?

I'm using Swift and trying to convert an Int (for example: -1333) to a byte array of 4 bytes. I was able to convert an Int to an array of 8 bytes (-1333 becomes [255, 255, 255, 255, 255, 255, 250, 203]), but I need it to be 4 bytes. I know that there are ways to do this in other languages like Java, but is there a way for Swift? Here's my code: (I used THIS answer)
func createByteArray(originalValue: Int)->[UInt8]{
var result:[UInt8]=Array()
var _number:Int = originalValue
let mask_8Bit=0xFF
var c=0
var size: Int = MemoryLayout.size(ofValue: originalValue)
for i in (0..<size).reversed(){
//at: 0 -> insert at the beginning of the array
result.insert(UInt8( _number&mask_8Bit),at:0)
_number >>= 8 //shift 8 times from left to right
}
return result
}
In Java an integer is always 32-bit, but in Swift it can be 32-bit or 64-bit, depending on the platform. Your code creates a byte array with the same size as that of the Int type, on a 64-bit platform that are 8 bytes.
If you want to restrict the conversion to 32-bit integers then use Int32 instead of Int, the result will then be an array of 4 bytes, independent of the platform.
An alternative conversion method is
let value: Int32 = -1333
let array = withUnsafeBytes(of: value.bigEndian, Array.init)
print(array) // [255, 255, 250, 203]
Or as a generic function for integer type of all sizes:
func byteArray<T>(from value: T) -> [UInt8] where T: FixedWidthInteger {
withUnsafeBytes(of: value.bigEndian, Array.init)
}
Example:
print(byteArray(from: -1333)) // [255, 255, 255, 255, 255, 255, 250, 203]
print(byteArray(from: Int32(-1333))) // [255, 255, 250, 203]
print(byteArray(from: Int16(-1333))) // [250, 203]
However, not like Java using big endian, iOS platform uses 'little endian' instead.
So if it would be
let value: Int32 = -1333
let array2 = withUnsafeBytes(of: value.littleEndian, Array.init)// [203, 250, 255, 255]
You can verify it by wrapping the value into data with below extension and check the bytes
extension FixedWidthInteger {
var data: Data {
let data = withUnsafeBytes(of: self) { Data($0) }
return data
}
}
value.data
Just a reminder for those iOS developers who are digging into memory layout.
It's hard for beginners to understand what is going on in the answers above
public extension FixedWidthInteger {
var bytes: [UInt8] {
withUnsafeBytes(of: bigEndian, Array.init)
}
}
First of all lets rewrite computed property bytes more detailed
var bytes: [UInt8] {
var copyOfSelf = self.bigEndian // this defines the order of bytes in result array
// for int '1' it can be [0, 0, 0, 0, 0, 0, 0, 1]
// or [1, 0, 0, 0, 0, 0, 0, 0]
return withUnsafeBytes(of: copyOfSelf) { urbp: UnsafeRawBufferPointer in
// Array has a constructor
// init<S>(_ s: S) where Element == S.Element, S : Sequence
// so 'UnsafeRawBufferPointer' confirms 'Sequence' protocol
// and 'urbp' can be passed as a parameter to Array constructor
return Array(urbp)
}
}
And here some tests to explain the result
final class FixedWidthIntegerTests: XCTestCase {
func testBytes() {
XCTAssertEqual([0,0,0,0,0,0,0,1], Int(1).bytes)
XCTAssertEqual([255,255,255,255,255,255,255,255], UInt.max.bytes)
XCTAssertEqual([127,255,255,255,255,255,255,255], Int.max.bytes)
XCTAssertEqual([1], Int8(1).bytes)
XCTAssertEqual([0,1], Int16(1).bytes)
XCTAssertEqual([0,0,0,1], Int32(1).bytes)
}
}

Better "nothing function" in Swift?

I have this structure,
typealias Tweak = (
grab:(_ p: SomeClass)->CGFloat,
change:(_ p: SomeClass, _ n: CGFloat)->(),
from:CGFloat, upto:CGFloat
)
(So, the first line "gives you a value", the second "changes something", the last two are just limits.)
So, you might have an array of such things ...
var tweaks:[Tweak] = [
({_ in 0}, {_ in}, 0,0),
( {p in mainHeight},
{p, n in
mainHeight = n
paintDisplayWhatever()},
8.0, 28.0),
( {p in Some.global},
{p, n in
Some.global = n
fireball.adjust(heat: n)},
8.0, 28.0),
etc
My question ...
notice the first one in the array, I simply wanted it to be the "nothing" version of a Tweak
So, I did this
nothingTweak: Tweak = ({_ in 0}, {_ in}, 0,0)
In Swift is there a better way to do the two "nothing" closures, or indeed, a more correct way to do the whole thing?
nothingTweak: Tweak = lessNilThanNil
you know?
There's no built-in value that represents "a closure which returns a 0 CGFloat value", let alone a tuple of them along with two other zero values.
However if you create a type, such as a struct, to represent a Tweak (rather than using a typealias of a tuple), you can define static constant(s) to represent "default" values of a Tweak. For example:
class SomeClass {}
struct Tweak {
// feel free to rename me to something more appropriate
static let zero = Tweak(grab: {_ in 0 }, change: {_ in }, from: 0, upto: 0)
var grab: (_ p: SomeClass) -> CGFloat
var change: (_ p: SomeClass, _ n: CGFloat) -> Void
var from: CGFloat
var upto: CGFloat
}
Now wherever a Tweak is expected, you can just say .zero to refer to your "zero default" (this is exactly what types like CGPoint do):
var tweaks: [Tweak] = [
.zero,
Tweak(
grab: { p in 25 },
change: { p, n in
print(p, n)
},
from: 8, upto: 28
),
Tweak(
grab: { p in 27 },
change: { p, n in
print(p, n * 4)
},
from: 8, upto: 28
)
]
Creating a structure is much more preferable to creating a typealias of a tuple in this case. Tuples are only really designed to be transient types, not to be used for long-term storage. Structures are much more powerful and suited for long-term use.

Retrieving a fixed amount of data from a Swift Array

I have var toPlotLines:[Int] = [200, 300, 400, 500, 600, 322, 435] and I want to retrieve the first four integers from the array. Can I do that without having to loop in Swift. I tried this graphView.graphPoints = toPlotLines[0..<n] where graphPoints is an empty integer array but, I keep getting this error:
Cannot subscript a value of type [int]
The error message is misleading. The problem is that toPlotLines[0 ..< n]
is not an Array but an ArraySlice:
The Array-like type that represents a sub-sequence of any Array, ContiguousArray, or other ArraySlice.
To create a "real array", use
graphView.graphPoints = Array(toPlotLines[0 ..< n])
From Array<Int> to ArraySlice<Int>
When you subscript to an Array, the type of the returned object is an ArraySlice:
let toPlotLines = [200, 300, 400, 500, 600, 322, 435] // type: [Int]
let arraySlice = toPlotLines[0 ..< 4] // type: ArraySlice<Int>
You can learn more about ArraySlice with ArraySlice Structure Reference.
From ArraySlice<Int> to Array<Int>
On one hand, ArraySlice conforms to CollectionType protocol that inherits itself from SequenceType. On the other hand, Array has an initializer init(_:) with the following declaration:
init<S : SequenceType where S.Generator.Element == _Buffer.Element>(_ s: S)
Therefore, it's possible to get a new Array from an ArraySlice easily:
let toPlotLines = [200, 300, 400, 500, 600, 322, 435]
let arraySlice = toPlotLines[0 ..< 4]
let newArray = Array(arraySlice)
print(newArray) // prints: [200, 300, 400, 500]
From ArraySlice<Int> to Array<String>
Because ArraySlice conforms to SequenceType, you can use map (or other functional methods like filter and reduce) on it. Thereby, you are not limited to get an Array<Int> from your ArraySlice<Int>: you can get an Array<String> (or any other array type that would make sense) from your ArraySlice<Int>.
let toPlotLines = [200, 300, 400, 500, 600, 322, 435]
let arraySlice = toPlotLines[0 ..< 4]
let stringArray = arraySlice.map { String($0) }
print(stringArray) // prints: ["200", "300", "400", "500"]