"sign" function in Swift

Swift 4

As has already been pointed out in @Wil Shipley's Swift 4 answer, there is now a sign property in the FloatingPoint protocol:

FloatingPointSign

The sign of a floating-point value.

Enumeration Cases

  • case minus The sign for a negative value.
  • case plus The sign for a positive value.

However, the comments to the sign blueprint in the source code of FloatingPoint contains important information that is (yet?) not present in the generated docs:

/// The sign of the floating-point value.
///
/// The `sign` property is `.minus` if the value's signbit is set, and
/// `.plus` otherwise. For example:
///
///     let x = -33.375
///     // x.sign == .minus
///
/// Do not use this property to check whether a floating point value is
/// negative. For a value `x`, the comparison `x.sign == .minus` is not
/// necessarily the same as `x < 0`. In particular, `x.sign == .minus` if
/// `x` is -0, and while `x < 0` is always `false` if `x` is NaN, `x.sign`
/// could be either `.plus` or `.minus`.

emphasizing, "... .minus if the value's signbit is set" and "Do not use this property to check whether a floating point value is negative".

Summa summarum: use the new sign property of the FloatingPoint protocol to actually check whether the value's signbit is set or not, but make sure to use some care if attempting to use this property to tell whether a number is negative or not.

var f: Float = 0.0

if case .minus = (-f).sign { print("A. f is negative!") }

f = -Float.nan

if f < 0 { print("B. f is negative!") }
if case .minus = f.sign { print("C. f is negative!") }

// A. f is negative!
// C. f is negative!

Swift 3

W.r.t. built-in functions, I think the closest you'll get is the Foundation method copysign(_: Double, _: Double) -> Double

let foo = -15.2
let sign = copysign(1.0, foo) // -1.0 (Double)

Naturally needing some type conversion in case you're not operating on a number of type Double.

However, I see no reason why not to create your own extension fit to your needs, especially for such a simple function as sign as they needn't get bloated, e.g.

extension IntegerType {
    func sign() -> Int {
        return (self < 0 ? -1 : 1)
    }
    /* or, use signature: func sign() -> Self */
}

extension FloatingPointType {
    func sign() -> Int {
        return (self < Self(0) ? -1 : 1)
    }
}

(here yielding 1 also for 0, as in the example in your question).


(Edit with regard to your comment below)

An alternative solution to the above would be to define your own protocol with a default implementation of sign(), so that all types conforming to this protocol would have access to that sign() method.

protocol Signable {
    init()
    func <(lhs:Self, rhs:Self) -> Bool
}

extension Signable {
    func sign() -> Int {
        return (self < Self() ? -1 : 1)
    }
}

/* extend signed integer types to Signable */
extension Int: Signable { }    // already have < and init() functions, OK
extension Int8 : Signable { }  // ...
extension Int16 : Signable { }
extension Int32 : Signable { }
extension Int64 : Signable { }

/* extend floating point types to Signable */
extension Double : Signable { }
extension Float : Signable { }
extension CGFloat : Signable { }

/* example usage */
let foo = -4.2
let bar = 42

foo.sign() // -1 (Int)
bar.sign() // 1  (Int)

The simd library has a sign method:

import simd

sign(-100.0) // returns -1
sign(100.0) // returns 1
sign(0.0) // returns 0

You get simd for free if you import SpriteKit.

Tags:

Swift