[swift-evolution] [Proposal draft] Enhanced floating-point protocols

Brent Royal-Gordon brent at architechies.com
Thu Apr 14 22:34:25 CDT 2016

First of all: I do *not* do crazy things with floating-point numbers, so there's a good chance I'm missing the point with some of this. Consider anything having to do with NaNs, subnormals, or other such strange denizens of the FPU to be prefixed with "I may be totally missing the point, but…"

> public protocol Arithmetic

Is there a rationale for the name "Arithmetic"? There's probably nothing wrong with it, but I would have guessed you'd use the name "Number".

> : Equatable, IntegerLiteralConvertible

Are there potential conforming types which aren't Comparable?

> func adding(rhs: Self) -> Self
> mutating func add(rhs: Self)

Is there a reason we're introducing methods and calling them from the operators, rather than listing the operators themselves as requirements?

>   func negate() -> Self

Should this be `negated()`? Should there be a mutating `negate()` variant, even if we won't have an operator for it?

(If a mutating `negate` would be an attractive nuisance, we can use `negative()`/`formNegative()` instead.)

>   /// NaN `payloads`.  `FloatingPoint` types should either treat inadmissible
>   /// payloads as zero, or mask them to create an admissible payload.
>   static func nan(payload payload: RawSignificand, signaling: Bool) -> Self

This seems unusually tolerant of bad inputs. Should this instead be a precondition, and have an (elidable in unchecked mode) trap if it's violated?

> static var greatestFiniteMagnitude: Self { get }
> static var leastNormalMagnitude: Self { get }
> static var leastMagnitude: Self { get }

Reading these, I find the use of "least" a little bit misleading—it seems like they should be negative. I wonder if instead, we can use ClosedIntervals/ClosedRanges to group together related values:

	static var positiveNormals: ClosedRange<Self> { get }
	static var positiveSubnormals: ClosedRange<Self> { get }

	Double.positiveNormals.upperBound		// DBL_MAX
	Double.positiveNormals.lowerBound		// DBL_MIN
	Double.positiveSubnormals.upperBound	// Self.positiveNormals.lowerBound.nextDown
	Double.positiveSubnormals.lowerBound	// 0.nextUp

	// Alternatively, you could have `positives`, running from 0.nextUp to infinity

Technically, you could probably implement calls like e.g. isNormal in terms of the positiveNormals property, but I'm sure separate calls are much, much faster.

(It might also be helpful if you could negate signed ClosedIntervals, which would negate and swap the bounds.)

> public protocol FloatingPoint: SignedArithmetic, Comparable {
>   func isLess(than other: Self) -> Bool
>   func totalOrder(with other: Self) -> Bool

Swift 2's Comparable demands a strict total order. However, the documentation here seems to imply that totalOrder is *not* what you get from the < operator. Is something getting reshuffled here?

>   init<Source: Integer>(_ value: Source)
>   init?<Source: Integer>(exactly value: Source)

>   init<Source: BinaryFloatingPoint>(_ value: Source)
>   init?<Source: BinaryFloatingPoint>(exactly value: Source)

It's great to have both of these, but I wonder how they're going to be implemented—if Integer can be either signed or unsigned, I'm not sure how you get the top bit of an unsigned integer out.

Also, since `init(_:)` is lossy and `init(exactly:)` is not, shouldn't their names technically be switched? Or perhaps `init(_:)` should be exact and trapping, `init(exactly:)` should be failable, and `init(closest:)` should always return something or other?

Brent Royal-Gordon

More information about the swift-evolution mailing list