Jens
1
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 FloatingPoints 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
?
1 Like
scanon
(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)
}
}
2 Likes
Jens
3
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
(Joe Groff)
4
x + copysign(m, self) should do the trick using standard IEEE-754 operations.
1 Like
Jens
5
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.
1 Like
Joe_Groff
(Joe Groff)
6
copysign/init(signOf:magnitudeOf:) should be a bitwise operation, and you're avoiding a branch, so I would hope so!
1 Like