Reputation: 35953
I have seen a similar question on SO but it does not answer everything I am asking here.
I have a function like this:
func myFunctionDouble (_ valores:[Double] = []) -> Array<Double> {
let numeroItens = valores.count
var c = [Double](repeating: 0,
count: numeroItens)
let factor : Double = Double.pi / Double(numeroItens)
for i in 0..<numeroItens {
var sum : Double = 0
for j in 0..<numeroItens {
sum = sum + valores[j] * cos ((Double(j) + 0.5) * Double(i) * factor)
}
c[i] = sum
}
return c;
}
I want to transform this function to deal with Double and Float.
I thought about replacing Double
with FloatingPoint
but it will simply not work and give me a bunch of errors.
There is no FloatingPoint.pi
or array c
cannot be declared like
var c = [FloatingPoint](repeating: 0, count: numeroItens)
is there a way to do that?
and more than that, how do I declare a var or an array to be of FloatingPoint
type, I mean, to accept both Float
and Double
?
Upvotes: 0
Views: 73
Reputation: 63252
Added on to @rmaddy's solution, you can drastically simplify your code by using higher order functions to remove all the "noise", things which are necessary for the computation, but aren't actually that specific to your computation.
func myFunction<T: FloatingPoint>(_ valores:[T] = []) -> Array<T>
where T: ExpressibleByFloatLiteral, T: Cosineable {
let factor: T = T.pi / T(valores.count)
return valores.indices.map { i in
return valores.enumerated()
.map { (offset, element) in
element * ((T(offset) + 0.5) * T(i) * factor).cosine()
}
.reduce(0, +)
}
}
From here, you can start labelling the terms better, and providing more context as to what these do.
The term element * ((T(offset) + 0.5) * T(i) * factor).cosine()
is faaaaarrrrr too complicated for a single expression. Why 0.5
? What's factor
? Why are we taking the cosine
? It's very non-obvious. Not only will strangers to this code not understand this, but over time, you yourself will forget about this and become a "stranger" to the code.
Upvotes: 2
Reputation: 318794
Following the example set forth in Rob's answer to How to use FloatingPoint generic type for Float/Double, you can do the following:
import Darwin // minimal necessary import
// importing Foundation, AppKit or UIKit also implicitly import Darwin
protocol Cosineable {
func cosine() -> Self
}
extension Float: Cosineable {
func cosine() -> Float { return cos(self) }
}
extension Double: Cosineable {
func cosine() -> Double { return cos(self) }
}
func myFunction<T: FloatingPoint>(_ valores:[T] = []) -> Array<T> where T: ExpressibleByFloatLiteral, T: Cosineable {
let numeroItens = valores.count
var c = [T](repeating: 0,
count: numeroItens)
let factor : T = T.pi / T(numeroItens)
for i in 0..<numeroItens {
var sum : T = 0
for j in 0..<numeroItens {
sum += valores[j] * ((T(j) + 0.5) * T(i) * factor).cosine()
}
c[i] = sum
}
return c
}
Upvotes: 2