 # Why no signum() on floating point types?

I tried but couldn't find any previous discussion about this, so:

`BinaryInteger` types have this method:

``````func signum() -> Self
``````

(which returns `-1` if this value is negative and `1` if it’s positive; otherwise, `0`.)

Is there a reason why this method shouldn't be available on floating point types too?
(Note that it's not the same as `FloatingPoint`s existing `sign` property.)

I guess things like -0 and +0, and nans with the sign bit set (or unset), infinity etc complicates it a bit, but what if it worked like the free function `sign(x)` that we get when importing simd:

``````sign(Double(0)) // 0
sign(-Double(0)) // 0
sign(Double.infinity) // 1
sign(-Double.infinity) // -1
sign(Double.nan) // 0
sign(-Double.nan) // 0
``````

?

(Steve Canon) #2

I didn't add it when I wrote the `FloatingPoint` protocols because:

(a) I've never found it to be very useful.
(b) It's not an IEEE 754 required operation.
(c) It's easily confused with the `sign` property, which is a required operation and has distinct semantics.

I didn't consider this, but it's also trivially implementable as an extension, and there's not much optimization opportunity. So it seems like a tough sell to me, unless there's a really compelling use.

It exists for `simd` because it's common in shader languages and somewhat more useful for vector programming than for scalar.

Anyway, if you want to have it:

``````extension FloatingPoint {
@inlinable
func signum( ) -> Self {
if self < 0 { return -1 }
if self > 0 { return 1 }
return 0
}
}
``````

or, probably worse code now, but more optimizable if we optimize some things in the stdlib and teach compiler how, something like:

``````extension FloatingPoint {
@inlinable
func signum( ) -> Self {
return Self(signOf: self, magnitudeOf: self == 0 || self.isNaN ? 0 : 1)
}
}
``````

FWIW, here's the piece of code where I noticed that it was missing:

``````    return self >= 0 ? x + abs(m) : x - abs(m)
// Would perhaps be more efficient if written:
// return x + m * self.signum() * m.signum()
``````

(In an extension to `BinaryFloatingPoint`)

(Joe Groff) #4

`x + copysign(m, self)` should do the trick using standard IEEE-754 operations.

or, as I just noticed:

``````return x + Self(signOf: self, magnitudeOf: m)
``````

which will work in the context of `BinaryFloatingPoint`.
No idea if it's any more efficient than:

``````return self >= 0 ? x + abs(m) : x - abs(m)
``````

though.

(Joe Groff) #6

`copysign`/`init(signOf:magnitudeOf:)` should be a bitwise operation, and you're avoiding a branch, so I would hope so!