Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift generic number types and math

I'm trying to wrap my head around the ins and outs of Swift generics and make some common math functions. I'm trying to implement a mod function, but not quite sure the best way to get it working using generics.

Here's what my mod function looks like:

func mod<N: NumericType, I: IntegerType>(_ x: N, _ y: I) -> N {
    return x - y * floor(x/y)
}

But I'm getting this error:

error: binary operator '/' cannot be applied to operands of type 'N' and 'I'
    return x - y * floor(x/y)

And here's my NumericType declaration for decimal and integer type numbers:

protocol NumericType: Comparable {
    static func +(lhs: Self, rhs: Self) -> Self
    static func -(lhs: Self, rhs: Self) -> Self
    static func *(lhs: Self, rhs: Self) -> Self
    static func /(lhs: Self, rhs: Self) -> Self
    static func %(lhs: Self, rhs: Self) -> Self
}

protocol DecimalType: NumericType {
    init(_ v: Double)
}

protocol IntegerType: NumericType {
    init(_ v: Int)
}

extension CGFloat : DecimalType { }
extension Double  : DecimalType { }
extension Float   : DecimalType { }

extension Int     : IntegerType { }
extension Int8    : IntegerType { }
extension Int16   : IntegerType { }
extension Int32   : IntegerType { }
extension Int64   : IntegerType { }
extension UInt    : IntegerType { }
extension UInt8   : IntegerType { }
extension UInt16  : IntegerType { }
extension UInt32  : IntegerType { }
extension UInt64  : IntegerType { }
like image 379
keegan3d Avatar asked Sep 08 '16 05:09

keegan3d


Video Answer


1 Answers

As of Swift 3, all floating point types conform to FloatingPoint, and all integer types conform to Integer. Both protocols define the basic arithmetic operations like +,-,*,/. Also the floor() function is defined for FloatingPoint arguments.

Therefore in your case I would define two implementations, one for integers and one for floating point values:

func mod<N: Integer>(_ x: N, _ y: N) -> N {
    return x - y * (x/y) // or just: return x % y
}

func mod<N: FloatingPoint>(_ x: N, _ y: N) -> N {
    return x - y * floor(x/y)
}

FloatingPoint has also a truncatingRemainder method, a.truncatingRemainder(b) is the "floating point equivalent" to a % b for integers. It gives the gives the same result as your mod function if both operands have the same sign.

like image 198
Martin R Avatar answered Oct 20 '22 12:10

Martin R