[Proposal draft] Enhanced floating-point protocols

but the documentation for Equatable and Comparable states that == and < must implement an equivalence relation and a strict total order, which is incompatible with the default IEEE-754 implementation of these operators when NaN values are involved. How do you resolve this conflict?

That’s a documentation bug; it should be relaxed by appending something like “… on non-exceptional values.”

I’ll quote Dave A. to put it a bit more formally:

To be clear, the semantic conformance of floating point types to Comparable depends on treating NaN as a "singular value”, i.e. outside the domain of valid arguments to < for the purposes of Comparable. That doesn’t mean we can’t nail down what < does for floating point types when it does get a NaN.

– Steve

···

On Apr 15, 2016, at 9:52 AM, Stephan Tolksdorf via swift-evolution <swift-evolution@swift.org> wrote:

I don’t see why this is needed; there isn't an AdditivelyInvertible protocol, why have MultiplicativelyInvertible? Are there (schoolbook arithmetic) types for which a terse inversion operation (i.e. `-num` or `1/num`) is not defined? For what it’s worth, “inverse” has so many definitions that “reciprocal” might be better if this must be defined; it has many fewer definitions.

Cheers,
Guillaume Lessard

···

On 15 avr. 2016, at 00:48, Nicola Salmoria via swift-evolution <swift-evolution@swift.org> wrote:

It might make sense to also have a

public protocol InvertibleArithmetic : Arithmetic {
func inverted() -> Self
}

FloatingPoint would conform to this protocol, returning 1/x, while integer types would not.

Thanks for the clarification!

- Stephan

···

On 2016-04-15, 18:58, Stephen Canon wrote:

but the documentation for Equatable and Comparable states that == and
< must implement an equivalence relation and a strict total order,
which is incompatible with the default IEEE-754 implementation of
these operators when NaN values are involved. How do you resolve this
conflict?

That’s a documentation bug; it should be relaxed by appending something
like “… on non-exceptional values.”

I’ll quote Dave A. to put it a bit more formally:

To be clear, the semantic conformance of floating point types to
Comparable depends on treating NaN as a "singular value”, i.e. outside
the domain of valid arguments to < /for the purposes of Comparable/.
That doesn’t mean we can’t nail down what < does for floating point
types when it does get a NaN.

Oh, a couple more things I just thought of:

> public protocol Arithmetic: Equatable, IntegerLiteralConvertible {
If your goals include supporting complex numbers, how is IntegerLiteralConvertible going to fit in there?

> /// Initialize to zero
> init()
0 is valuable as the additive identity. Should there also be a way to get 1, the multiplicative identity? If you need both, should these be static properties instead of initializers?

Interestingly, these two questions are related.

If you expose the multiplicative identity, you automatically expose a natural way to convert from an integer N: just add `one` to itself N times.
If N is negative, take the opposite.

For complex numbers the multiplicative identity is 1 + 0i, so this means that Complex(N) = N + 0i.

As an aside, a default generic implementation of IntegerLiteralConvertible would run in O(log N) steps, using the “double-and-add” algorithm:
Elliptic curve point multiplication - Wikipedia.
Though I don’t think this is particularly useful for our use case :-)

···


Nicola

Hi Howard, thanks for the feedback.

    +1 great addition.

    Would suggest the naming could be more consistent, in particular:

    1 Anything returning Self could be named xxxed. In the current proposal this
      naming convention is sometimes used, e.g. divided, and sometimes not, e.g.
      subtracting. Suggest all unified with the xxxed convention.

The names in the Arithmetic protocol are Dave A’s creation, but I think they’re
a reasonable compromise given the constraints placed on us. While consistency
would be nice, I think that clarity at use site is more important, under the
rationale that code is read more often than written. Also, keep in mind that in
practice, “everyone” will use the operators for arithmetic. Dave may have more
to say on the subject.

    1 Anything returning Bool could be named isXxx. In some cases this is used,
      e.g. isUnordered, but not others, e.g. totalOrder.

FWIW, that is a much more restrictive constraint than what our API guidelines
specify. They say the usage should read as an assertion about the
receiver, e.g.

    person.hasTooManyCats
    waterSupply.containsUnsafeLevelsOfLead

are fine.

···

on Thu Apr 14 2016, Stephen Canon <swift-evolution@swift.org> wrote:

    On Apr 14, 2016, at 6:05 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

That’s a reasonable point. isTotallyOrdered(with: ) is simple, but I’m not sure
how I would handle totalOrderMagnitude( ) under this scheme. Thoughts?

Thanks,
– Steve

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

I'd like to have something like Summable with 'add', 'adding' and 'zero' being a
separate protocol as well as somthing like Multiplicative with 'multiply',
'multiplied' and 'one' being a separate protocol, because these are universally
interesting for other cases, e.g. Summable would be useful for defining path
lengths in a graph library.

Would you mind adding that to the proposal?

I suspect you may be headed into the realm of
protocols-as-bags-of-syntax. I'm guessing Summable should probably be
Monoid <https://en.wikipedia.org/wiki/Monoid&gt; and the Multiplicative
one, likely Ring <https://en.wikipedia.org/wiki/Ring_(mathematics)&gt;\.

Creating and using a lattice of Swift protocols for Algebraic Structures
<https://en.wikipedia.org/wiki/Algebraic_structure&gt; is a research
project. Look at pages 14 and 24 of
<http://www.cs.indiana.edu/pub/techreports/TR638.pdf&gt;—which does the job
right for C++—and you'll see why. That level of complexity probably
shouldn't appear at the top level of the standard library, and really
needs a family of generic algorithms to justify it. Ideally, all of
this would be researched and developed outside the standard library and
possibly incorporated when it is established existing practice. IMO
it's definitely not a realm the standard library should enter casually
by throwing in a couple of protocols based around addition and
multiplication.

Cheers,
Dave

···

on Tue Apr 19 2016, Thorsten Seitz <swift-evolution@swift.org> wrote:

Am 15.04.2016 um 01:55 schrieb Stephen Canon via swift-evolution > <swift-evolution@swift.org>:

    Enhanced floating-point protocols

    * Proposal: SE-NNNN
    * Author(s): Stephen Canon
    * Status: Awaiting review
    * Review manager: TBD

SVG ImageIntroduction

    The current FloatingPoint protocol is quite limited, and provides only a
    small subset of the features expected of an IEEE 754 conforming type. This
    proposal expands the protocol to cover most of the expected basic
    operations, and adds a second protocol, BinaryFloatingPoint, that provides a
    number of useful tools for generic programming with the most commonly used
    types.

SVG ImageMotivation

    Beside the high-level motivation provided by the introduction, the proposed
    prototype schema addresses a number of issues and requests that we've
    received from programmers:

    * FloatingPoint should conform to Equatable, and Comparable
    * FloatingPoint should conform to FloatLiteralConvertible
    * Deprecate the % operator for floating-point types
    * Provide basic constants (analogues of C's DBL_MAX, etc.)
    * Make Float80 conform to FloatingPoint

    It also puts FloatingPoint much more tightly in sync with the work that is
    being done on protocols for Integers, which will make it easier to provide a
    uniform interface for arithmetic scalar types.

SVG ImageDetailed design

    A new protocol, Arithmetic, is introduced that provides the most basic
    operations (add, subtract, multiply and divide) as well as Equatable and
    IntegerLiteralConvertible, and is conformed to by both integer and floating-
    point types.

    There has been some resistance to adding such a protocol, owing to
    differences in behavior between floating point and integer arithmetic. While
    these differences make it difficult to write correct generic code that
    operates on all "arithmetic" types, it is nonetheless convenient to provide
    a single protocol that guarantees the availability of these basic
    operations. It is intended that "number-like" types should provide these
    APIs.

    /// Arithmetic protocol declares methods backing binary arithmetic operators,
/// such as `+`, `-` and `*`; and their mutating counterparts. These methods
/// operate on arguments of the same type.
///
/// Both mutating and non-mutating operations are declared in the protocol, but
/// only the mutating ones are required. Should conforming type omit
/// non-mutating implementations, they will be provided by a protocol extension.
/// Implementation in that case will copy `self`, perform a mutating operation
/// on it and return the resulting value.
public protocol Arithmetic: Equatable, IntegerLiteralConvertible {
  /// Initialize to zero
  init()

  /// The sum of `self` and `rhs`.
  // Arithmetic provides a default implementation of this method in terms
  // of the mutating `add` operation.
  @warn_unused_result
  func adding(rhs: Self) -> Self

  /// Adds `rhs` to `self`.
  mutating func add(rhs: Self)

  /// The result of subtracting `rhs` from `self`.
  // Arithmetic provides a default implementation of this method in terms
  // of the mutating `subtract` operation.
  @warn_unused_result
  func subtracting(rhs: Self) -> Self

  /// Subtracts `rhs` from `self`.
  mutating func subtract(rhs: Self)

  /// The product of `self` and `rhs`.
  // Arithmetic provides a default implementation of this method in terms
  // of the mutating `multiply` operation.
  @warn_unused_result
  func multiplied(by rhs: Self) -> Self

  /// Multiplies `self` by `rhs`.
  mutating func multiply(by rhs: Self)

  /// The quotient of `self` dividing by `rhs`.
  // Arithmetic provides a default implementation of this method in terms
  // of the mutating `divide` operation.
  @warn_unused_result
  func divided(by rhs: Self) -> Self

  /// Divides `self` by `rhs`.
  mutating func divide(by rhs: Self)
}

/// SignedArithmetic protocol will only be conformed to by signed numbers,
/// otherwise it would be possible to negate an unsigned value.
///
/// The only method of this protocol has the default implementation in an
/// extension, that uses a parameterless initializer and subtraction.
public protocol SignedArithmetic : Arithmetic {
  func negate() -> Self
}

    The usual arithmetic operators are then defined in terms of the
    implementation hooks provided by Arithmetic and SignedArithmetic, so
    providing those operations are all that is necessary for a type to present a
    "number-like" interface.

    The FloatingPoint protocol is split into two parts; FloatingPoint and
    BinaryFloatingPoint, which conforms to FloatingPoint. If decimal types were
    added at some future point, they would conform to DecimalFloatingPoint.

    FloatingPoint is expanded to contain most of the IEEE 754 basic operations,
    as well as conformance to SignedArithmetic and Comparable.

    /// A floating-point type that provides most of the IEEE 754 basic (clause 5)
/// operations. The base, precision, and exponent range are not fixed in
/// any way by this protocol, but it enforces the basic requirements of
/// any IEEE 754 floating-point type.
///
/// The BinaryFloatingPoint protocol refines these requirements and provides
/// some additional useful operations as well.
public protocol FloatingPoint: SignedArithmetic, Comparable {

  /// An unsigned integer type that can represent the significand of any value.
  ///
  /// The significand (http://en.wikipedia.org/wiki/Significand\) is frequently
  /// also called the "mantissa", but this terminology is slightly incorrect
  /// (see the "Use of 'mantissa'" section on the linked Wikipedia page for
  /// more details). "Significand" is the preferred terminology in IEEE 754.
  associatedtype RawSignificand: UnsignedInteger

  /// 2 for binary floating-point types, 10 for decimal.
  ///
  /// A conforming type may use any integer radix, but values other than
  /// 2 or 10 are extraordinarily rare in practice.
  static var radix: Int { get }

  /// Positive infinity. Compares greater than all finite numbers.
  static var infinity: Self { get }

  /// A quiet NaN (not-a-number). Compares not equal to every value,
  /// including itself.
  static var nan: Self { get }

  /// NaN with specified `payload`.
  ///
  /// Compares not equal to every value, including itself. Most operations
  /// with a NaN operand will produce a NaN result. Note that it is generally
  /// not the case that all possible significand values are valid
  /// NaN `payloads`. `FloatingPoint` types should either treat inadmissible
  /// payloads as zero, or mask them to create an admissible payload.
  @warn_unused_result
  static func nan(payload payload: RawSignificand, signaling: Bool) -> Self

  /// The greatest finite number.
  ///
  /// Compares greater than or equal to all finite numbers, but less than
  /// infinity. Corresponds to the C macros `FLT_MAX`, `DBL_MAX`, etc.
  /// The naming of those macros is slightly misleading, because infinity
  /// is greater than this value.
  static var greatestFiniteMagnitude: Self { get }

  // NOTE: Rationale for "ulp" instead of "epsilon":
  // We do not use that name because it is ambiguous at best and misleading
  // at worst:
  //
  // - Historically several definitions of "machine epsilon" have commonly
  // been used, which differ by up to a factor of two or so. By contrast
  // "ulp" is a term with a specific unambiguous definition.
  //
  // - Some languages have used "epsilon" to refer to wildly different values,
  // such as `leastMagnitude`.
  //
  // - Inexperienced users often believe that "epsilon" should be used as a
  // tolerance for floating-point comparisons, because of the name. It is
  // nearly always the wrong value to use for this purpose.

  /// The unit in the last place of 1.0.
  ///
  /// This is the weight of the least significant bit of the significand of 1.0,
  /// or the positive difference between 1.0 and the next greater representable
  /// number. Corresponds to the C macros `FLT_EPSILON`, `DBL_EPSILON`, etc.
  static var ulp: Self { get }

  /// The unit in the last place of `self`.
  ///
  /// This is the unit of the least significant digit in the significand of
  /// `self`. For most numbers `x`, this is the difference between `x` and
  /// the next greater (in magnitude) representable number. There are some
  /// edge cases to be aware of:
  ///
  /// - `greatestFiniteMagnitude.ulp` is a finite number, even though
  /// the next greater representable value is `infinity`.
  /// - `x.ulp` is `NaN` if `x` is not a finite number.
  /// - If `x` is very small in magnitude, then `x.ulp` may be a subnormal
  /// number. On targets that do not support subnormals, `x.ulp` may be
  /// flushed to zero.
  ///
  /// This quantity, or a related quantity is sometimes called "epsilon" or
  /// "machine epsilon". We avoid that name because it has different meanings
  /// in different languages, which can lead to confusion, and because it
  /// suggests that it is an good tolerance to use for comparisons,
  /// which is almost never is.
  ///
  /// (See Machine epsilon - Wikipedia for more detail)
  var ulp: Self { get }

  /// The least positive normal number.
  ///
  /// Compares less than or equal to all positive normal numbers. There may
  /// be smaller positive numbers, but they are "subnormal", meaning that
  /// they are represented with less precision than normal numbers.
  /// Corresponds to the C macros `FLT_MIN`, `DBL_MIN`, etc. The naming of
  /// those macros is slightly misleading, because subnormals, zeros, and
  /// negative numbers are smaller than this value.
  static var leastNormalMagnitude: Self { get }

  /// The least positive number.
  ///
  /// Compares less than or equal to all positive numbers, but greater than
  /// zero. If the target supports subnormal values, this is smaller than
  /// `leastNormalMagnitude`; otherwise they are equal.
  static var leastMagnitude: Self { get }

  /// `true` iff the signbit of `self` is set. Implements the IEEE 754
  /// `signbit` operation.
  ///
  /// Note that this is not the same as `self < 0`. In particular, this
  /// property is true for `-0` and some NaNs, both of which compare not
  /// less than zero.
  // TODO: strictly speaking a bit and a bool are slightly different
  // concepts. Is another name more appropriate for this property?
  // `isNegative` is incorrect because of -0 and NaN. `isSignMinus` might
  // be acceptable, but isn't great. `signBit` is the IEEE 754 name.
  var signBit: Bool { get }

  /// The integer part of the base-r logarithm of the magnitude of `self`,
  /// where r is the radix (2 for binary, 10 for decimal). Implements the
  /// IEEE 754 `logB` operation.
  ///
  /// Edge cases:
  ///
  /// - If `x` is zero, then `x.exponent` is `Int.min`.
  /// - If `x` is +/-infinity or NaN, then `x.exponent` is `Int.max`
  var exponent: Int { get }

  /// The significand satisfies:
  ///
  /// ~~~
  /// self = (signBit ? -1 : 1) * significand * radix**exponent
  /// ~~~
  ///
  /// If radix is 2 (the most common case), then for finite non-zero numbers
  /// `1 <= significand` and `significand < 2`. For other values of `x`,
  /// `x.significand` is defined as follows:
  ///
  /// - If `x` is zero, then `x.significand` is 0.0.
  /// - If `x` is infinity, then `x.significand` is 1.0.
  /// - If `x` is NaN, then `x.significand` is NaN.
  ///
  /// For all floating-point `x`, if we define y by:
  ///
  /// ~~~
  /// let y = Self(signBit: x.signBit, exponent: x.exponent,
  /// significand: x.significand)
  /// ~~~
  ///
  /// then `y` is equivalent to `x`, meaning that `y` is `x` canonicalized.
  var significand: Self { get }

  /// Initialize from signBit, exponent, and significand.
  ///
  /// The result is:
  ///
  /// ~~~
  /// (signBit ? -1 : 1) * significand * radix**exponent
  /// ~~~
  ///
  /// (where `**` is exponentiation) computed as if by a single correctly-
  /// rounded floating-point operation. If this value is outside the
  /// representable range of the type, overflow or underflow occurs, and zero,
  /// a subnormal value, or infinity may result, as with any basic operation.
  /// Other edge cases:
  ///
  /// - If `significand` is zero or infinite, the result is zero or infinite,
  /// regardless of the value of `exponent`.
  ///
  /// - If `significand` is NaN, the result is NaN.
  ///
  /// Note that for any floating-point `x` the result of
  ///
  /// `Self(signBit: x.signBit,
  /// exponent: x.exponent,
  /// significand: x.significand)`
  ///
  /// is "the same" as `x`; it is `x` canonicalized.
  ///
  /// Because of these properties, this initializer implements the IEEE 754
  /// `scaleB` operation.
  init(signBit: Bool, exponent: Int, significand: Self)

  /// A floating point value whose exponent and signficand are taken from
  /// `magnitude` and whose signBit is taken from `signOf`. Implements the
  /// IEEE 754 `copysign` operation.
  // TODO: better argument names would be great.
  init(magnitudeOf magnitude: Self, signOf: Self)

  /// The least representable value that compares greater than `self`.
  ///
  /// - If `x` is `-infinity`, then `x.nextUp` is `-greatestMagnitude`.
  /// - If `x` is `-leastMagnitude`, then `x.nextUp` is `-0.0`.
  /// - If `x` is zero, then `x.nextUp` is `leastMagnitude`.
  /// - If `x` is `greatestMagnitude`, then `x.nextUp` is `infinity`.
  /// - If `x` is `infinity` or `NaN`, then `x.nextUp` is `x`.
  var nextUp: Self { get }

  /// The greatest representable value that compares less than `self`.
  ///
  /// `x.nextDown` is equivalent to `-(-x).nextUp`
  var nextDown: Self { get }

  /// Remainder of `self` divided by `other`.
  ///
  /// For finite `self` and `other`, the remainder `r` is defined by
  /// `r = self - other*n`, where `n` is the integer nearest to `self/other`.
  /// (Note that `n` is *not* `self/other` computed in floating-point
  /// arithmetic, and that `n` may not even be representable in any available
  /// integer type). If `self/other` is exactly halfway between two integers,
  /// `n` is chosen to be even.
  ///
  /// It follows that if `self` and `other` are finite numbers, the remainder
  /// `r` satisfies `-|other|/2 <= r` and `r <= |other|/2`.
  ///
  /// `formRemainder` is always exact, and therefore is not affected by
  /// rounding modes.
  mutating func formRemainder(dividingBy other: Self)

  /// Remainder of `self` divided by `other` using truncating division.
  ///
  /// If `self` and `other` are finite numbers, the truncating remainder
  /// `r` has the same sign as `other` and is strictly smaller in magnitude.
  /// It satisfies `r = self - other*n`, where `n` is the integral part
  /// of `self/other`.
  ///
  /// `formTruncatingRemainder` is always exact, and therefore is not
  /// affected by rounding modes.
  mutating func formTruncatingRemainder(dividingBy other: Self)

  /// Mutating form of square root.
  mutating func formSquareRoot( )

  /// Fused multiply-add, accumulating the product of `lhs` and `rhs` to `self`.
  mutating func addProduct(lhs: Self, _ rhs: Self)

  /// Remainder of `self` divided by `other`.
  @warn_unused_result
  func remainder(dividingBy other: Self) -> Self

  /// Remainder of `self` divided by `other` using truncating division.
  @warn_unused_result
  func truncatingRemainder(dividingBy other: Self) -> Self

  /// Square root of `self`.
  @warn_unused_result
  func squareRoot( ) -> Self

  /// `self + lhs*rhs` computed without intermediate rounding.
  @warn_unused_result
  func addingProduct(lhs: Self, _ rhs: Self) -> Self

  /// The minimum of `x` and `y`. Implements the IEEE 754 `minNum` operation.
  ///
  /// Returns `x` if `x <= y`, `y` if `y < x`, and whichever of `x` or `y`
  /// is a number if the other is NaN. The result is NaN only if both
  /// arguments are NaN.
  ///
  /// This function is an implementation hook to be used by the free function
  /// min(Self, Self) -> Self so that we get the IEEE 754 behavior with regard
  /// to NaNs.
  @warn_unused_result
  static func minimum(x: Self, _ y: Self) -> Self

  /// The maximum of `x` and `y`. Implements the IEEE 754 `maxNum` operation.
  ///
  /// Returns `x` if `x >= y`, `y` if `y > x`, and whichever of `x` or `y`
  /// is a number if the other is NaN. The result is NaN only if both
  /// arguments are NaN.
  ///
  /// This function is an implementation hook to be used by the free function
  /// max(Self, Self) -> Self so that we get the IEEE 754 behavior with regard
  /// to NaNs.
  @warn_unused_result
  static func maximum(x: Self, _ y: Self) -> Self

  /// Whichever of `x` or `y` has lesser magnitude. Implements the IEEE 754
  /// `minNumMag` operation.
  ///
  /// Returns `x` if abs(x) <= abs(y), `y` if abs(y) < abs(x), and whichever of
  /// `x` or `y` is a number if the other is NaN. The result is NaN
  /// only if both arguments are NaN.
  @warn_unused_result
  static func minimumMagnitude(x: Self, _ y: Self) -> Self

  /// Whichever of `x` or `y` has greater magnitude. Implements the IEEE 754
  /// `maxNumMag` operation.
  ///
  /// Returns `x` if abs(x) >= abs(y), `y` if abs(y) > abs(x), and whichever of
  /// `x` or `y` is a number if the other is NaN. The result is NaN
  /// only if both arguments are NaN.
  @warn_unused_result
  static func maximumMagnitude(x: Self, _ y: Self) -> Self

  /// IEEE 754 equality predicate.
  ///
  /// -0 compares equal to +0, and NaN compares not equal to anything,
  /// including itself.
  @warn_unused_result
  func isEqual(to other: Self) -> Bool

  /// IEEE 754 less-than predicate.
  ///
  /// NaN compares not less than anything. -infinity compares less than
  /// all values except for itself and NaN. Everything except for NaN and
  /// +infinity compares less than +infinity.
  @warn_unused_result
  func isLess(than other: Self) -> Bool

  /// IEEE 754 less-than-or-equal predicate.
  ///
  /// NaN compares not less than or equal to anything, including itself.
  /// -infinity compares less than or equal to everything except NaN.
  /// Everything except NaN compares less than or equal to +infinity.
  ///
  /// Because of the existence of NaN in FloatingPoint types, trichotomy does
  /// not hold, which means that `x < y` and `!(y <= x)` are not equivalent.
  /// This is why `isLessThanOrEqual(to:)` is a separate implementation hook
  /// in the protocol.
  ///
  /// Note that this predicate does not impose a total order. The `totalOrder`
  /// predicate provides a refinement satisfying that criteria.
  @warn_unused_result
  func isLessThanOrEqual(to other: Self) -> Bool

  /// IEEE 754 unordered predicate. True if either `self` or `other` is NaN,
  /// and false otherwise.
  @warn_unused_result
  func isUnordered(with other: Self) -> Bool

  /// True if and only if `self` is normal.
  ///
  /// A normal number uses the full precision available in the format. Zero
  /// is not a normal number.
  var isNormal: Bool { get }

  /// True if and only if `self` is finite.
  ///
  /// If `x.isFinite` is `true`, then one of `x.isZero`, `x.isSubnormal`, or
  /// `x.isNormal` is also `true`, and `x.isInfinite` and `x.isNan` are
  /// `false`.
  var isFinite: Bool { get }

  /// True iff `self` is zero. Equivalent to `self == 0`.
  var isZero: Bool { get }

  /// True if and only if `self` is subnormal.
  ///
  /// A subnormal number does not use the full precision available to normal
  /// numbers of the same format. Zero is not a subnormal number.
  var isSubnormal: Bool { get }

  /// True if and only if `self` is infinite.
  ///
  /// Note that `isFinite` and `isInfinite` do not form a dichotomy, because
  /// they are not total. If `x` is `NaN`, then both properties are `false`.
  var isInfinite: Bool { get }

  /// True if and only if `self` is NaN ("not a number").
  var isNan: Bool { get }

  /// True if and only if `self` is a signaling NaN.
  var isSignalingNan: Bool { get }

  /// The IEEE 754 "class" of this type.
  var floatingPointClass: FloatingPointClassification { get }

  /// True if and only if `self` is canonical.
  ///
  /// Every floating-point value of type Float or Double is canonical, but
  /// non-canonical values of type Float80 exist, and non-canonical values
  /// may exist for other types that conform to FloatingPoint.
  ///
  /// The non-canonical Float80 values are known as "pseudo-denormal",
  /// "unnormal", "pseudo-infinity", and "pseudo-NaN".
  /// (Extended precision - Wikipedia)
  var isCanonical: Bool { get }

  /// True if and only if `self` preceeds `other` in the IEEE 754 total order
  /// relation.
  ///
  /// This relation is a refinement of `<=` that provides a total order on all
  /// values of type `Self`, including non-canonical encodings, signed zeros,
  /// and NaNs. Because it is used much less frequently than the usual
  /// comparisons, there is no operator form of this relation.
  @warn_unused_result
  func totalOrder(with other: Self) -> Bool

  /// True if and only if `abs(self)` preceeds `abs(other)` in the IEEE 754
  /// total order relation.
  @warn_unused_result
  func totalOrderMagnitude(with other: Self) -> Bool

  /// The closest representable value to the argument.
  init<Source: Integer>(_ value: Source)

  /// Fails if the argument cannot be exactly represented.
  init?<Source: Integer>(exactly value: Source)
}

    The BinaryFloatingPoint protocol provides a number of additional APIs that
    only make sense for types with fixed radix 2:

    /// A radix-2 (binary) floating-point type that follows the IEEE 754 encoding
/// conventions.
public protocol BinaryFloatingPoint: FloatingPoint {

  /// The number of bits used to represent the exponent.
  ///
  /// Following IEEE 754 encoding convention, the exponent bias is:
  ///
  /// bias = 2**(exponentBitCount-1) - 1
  ///
  /// The least normal exponent is `1-bias` and the largest finite exponent
  /// is `bias`. The all-zeros exponent is reserved for subnormals and zeros,
  /// and the all-ones exponent is reserved for infinities and NaNs.
  static var exponentBitCount: Int { get }

  /// For fixed-width floating-point types, this is the number of fractional
  /// significand bits.
  ///
  /// For extensible floating-point types, `significandBitCount` should be
  /// the maximum allowed significand width (without counting any leading
  /// integral bit of the significand). If there is no upper limit, then
  /// `significandBitCount` should be `Int.max`.
  ///
  /// Note that `Float80.significandBitCount` is 63, even though 64 bits
  /// are used to store the significand in the memory representation of a
  /// `Float80` (unlike other floating-point types, `Float80` explicitly
  /// stores the leading integral significand bit, but the
  /// `BinaryFloatingPoint` APIs provide an abstraction so that users don't
  /// need to be aware of this detail).
  static var significandBitCount: Int { get }

  /// The raw encoding of the exponent field of the floating-point value.
  var exponentBitPattern: UInt { get }

  /// The raw encoding of the significand field of the floating-point value.
  ///
  /// `significandBitPattern` does *not* include the leading integral bit of
  /// the significand, even for types like `Float80` that store it explicitly.
  var significandBitPattern: RawSignificand { get }

  /// Combines `signBit`, `exponent` and `significand` bit patterns to produce
  /// a floating-point value.
  init(signBit: Bool,
       exponentBitPattern: UInt,
       significandBitPattern: RawSignificand)

  /// The least-magnitude member of the binade of `self`.
  ///
  /// If `x` is `+/-significand * 2**exponent`, then `x.binade` is
  /// `+/- 2**exponent`; i.e. the floating point number with the same sign
  /// and exponent, but with a significand of 1.0.
  var binade: Self { get }

  /// The number of bits required to represent significand.
  ///
  /// If `self` is not a finite non-zero number, `significandWidth` is
  /// `-1`. Otherwise, it is the number of bits required to represent the
  /// significand exactly (less `1` because common formats represent one bit
  /// implicitly).
  var significandWidth: Int { get }

  @warn_unused_result
  func isEqual<Other: BinaryFloatingPoint>(to other: Other) -> Bool

  @warn_unused_result
  func isLess<Other: BinaryFloatingPoint>(than other: Other) -> Bool

  @warn_unused_result
  func isLessThanOrEqual<Other: BinaryFloatingPoint>(to other: Other) -> Bool

  @warn_unused_result
  func isUnordered<Other: BinaryFloatingPoint>(with other: Other) -> Bool

  @warn_unused_result
  func totalOrder<Other: BinaryFloatingPoint>(with other: Other) -> Bool

  /// `value` rounded to the closest representable value.
  init<Source: BinaryFloatingPoint>(_ value: Source)

  /// Fails if `value` cannot be represented exactly as `Self`.
  init?<Source: BinaryFloatingPoint>(exactly value: Source)
}

    Float, Double, Float80 and CGFloat will conform to all of these protocols.

    A small portion of the implementation of these APIs is dependent on new
    Integer protocols that will be proposed separately. Everything else is
    implemented in draft form on the branch floating-point-revision of my fork.

SVG ImageImpact on existing code

    1 The % operator is no longer available for FloatingPoint types. We
      don't believe that it was widely used correctly, and the operation is
      still available via the formTruncatingRemainder method for people who need
      it.

    2 To follow the naming guidelines, NaN and isNaN are replaced with nan
      and isNan.

    3 The redundant property quietNaN is removed.

    4 isSignaling is renamed isSignalingNan.

SVG ImageAlternatives considered

    N/A.

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org
    https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

Provide basic constants (analogues of C's DBL_MAX, etc.)

Nice, have you considered adding pi/e and other common constants? I’d really really like to see use of M_PI go away… :-)

That’s a reasonable suggestion. I’m not sure if FloatingPoint is the right protocol to attach them to, but I’m not sure that it’s wrong either. I’d be interested to hear arguments from the community either way.

I’m not sure where the right place is either, I just want them :-) Seriously though, the notion of pi seems to make sense for both decimal and binary fp types, it seems base independent.

Swift supports instance and type members with the same names, but this is controversial, leads to confusion, and may go away in the future. It would be great to avoid this in your design.

Interesting. Both are definitely useful, but Type(1).ulp is sufficiently simple that only having the instance member may be good enough. Otherwise, ulpOfOne or similar could work.

Either of those work for me.

I’m certainly not a floating point guru, but I would have expected significant to be of type RawSignificand, and thought that the significant of a nan would return its payload. Does this approach make sense?

… later: I see that you have this on the binary FP type, so I assume there is a good reason for this :-)

Both are useful to have in practice. I have been attempting to keep the assumptions about representation to a minimum in the top-level FloatingPoint protocol.

Makes sense!

I’m used to this being called a “Denormal”, but I suspect that “subnormal” is the actually right name? Maybe it would be useful to mention the “frequently known as denormal” in the comment, like you did with mantissa earlier.

Yes, “subnormal” is the preferred IEEE 754 terminology, but I’ll add a note referencing “denormal” as well.

Thanks!

-Chris

···

On Apr 14, 2016, at 9:49 PM, Stephen Canon <scanon@apple.com> wrote:

On Apr 14, 2016, at 4:55 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Erica, thanks for the feedback.

* I do use % for floating point but not as much as I first thought before I started searching through my code after reading your e-mail. But when I do use it, it's nice to have a really familiar symbol rather than a big word. What were the ways that it was used incorrectly? Do you have some examples?

As it happens, I have a rationale sitting around from an earlier (internal) discussion:

Thanks. That makes plenty of sense although I do still think the name is long and hard to discover compared to fmod[1] and %.

* I don't quite get how equatable is going to work. Do you mind explaining that in more detail?

I’m not totally sure what your question is. Are you asking how FloatingPoint will conform to Equatable, or how the Equatable protocol will work?

Given the many words and passionate articles about how difficult it is to perform floating point comparisons,
for example, Comparing Floating Point Numbers, 2012 Edition | Random ASCII – tech blog of Bruce Dawson,
I'm just curious as to what approach you've settled on. The topic has come up on-list quite a few times.

-- E

[1] Nearly all of what I *thought* I was doing with % did turn out to be fmod (CGFloat a = fmodf(stepAngle * i, 360.0))
so there's that

···

On Apr 14, 2016, at 10:36 PM, Stephen Canon <scanon@apple.com> wrote:

On Apr 14, 2016, at 6:29 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Are there potential conforming types which aren't Comparable?

Not at present, but I expect there to be in the future. Modular integers and complex numbers come to mind as the most obvious examples.

Ooh, those are great examples. That is definitely the right decision, then.

(One thing I've been vaguely concerned with is dimensional analysis. A strong type system opens up the possibility of marking numbers with units, or at least dimensions, so that the type system can catch when you try to pass a Second<Pound<T>> to a call that's expecting a Second<Newton<T>>. Doing this properly requires more freedom in the multiplication and division operators' parameters and return values—but of course, it also requires higher-kinded types to construct the right return values, so it's out of reach for Swift 3 anyway.)

/// 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?

I don’t think that it’s a particularly useful error to detect,

Maybe it's just my lack of knowledge, but I feel like, if you are calling this method, you probably care about getting that payload into the resulting NaN. Otherwise you would be using the `nan` property. (There is no `signalingNan` property, but there could be.)

What do people use NaN payloads for? Are there a lot of cases where the payload is a nice-to-have, but it's okay to destroy or even mangle it?

and different floating point types may differ greatly in what payloads they support (if any), because they might choose to reserve those encodings for other purposes.

If the data you can actually get into a NaN varies so much from one type to another, is this API a useful one to offer on the protocol? Is it something you can reliably use on "any floating-point type" without knowing which type it is?

(It also now occurs to me that this might be better off as an initializer: `init(nanWithPayload:signaling:)`.)

Reading these, I find the use of "least" a little bit misleading—it seems like they should be negative.

Magnitudes are strictly positive. In fairness, that may not be immediately obvious to all readers.

It does make sense now that you've said so! It might be a good doc comment note, though.

  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

This seems wildly over-engineered to me personally. Every language I surveyed provides (a subset of) these quantities as simple scalar values.

Well, I am rather prone to wild over-engineering. :^)

One place where a range like FloatingPoint.positives would be useful is in random number generation. Suppose you have:

  protocol Randomizer {
    …
    mutating func choice<T: FloatingPoint>(from choices: ClosedRange<T>) -> T
    …
  }

Which lets you say:

  rng.choice(from: 0...1)

It would then be nice to say something like:

  rng.choice(from: Double.positives)
  rng.choice(from: Float.finites)
  // etc.

Of course, the set of ranges useful for that purpose is probably different from these more technical things, so that might not be the best design anyway.

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?

The Swift 2 Comparable documentation is probably overly specific. The requirement should really be something like a strict total order on non-exceptional values.

Okay.

(While I was waiting for your reply, I was thinking about a rework of `Comparable` which had a sort-oriented `totalOrder(_:)` as a requirement and `isLess(_:)`, `isGreater(_:)`, et. al. which defaulted to using `totalOrder(_:)`, but could be overridden for types like FloatingPoint with exceptional values. I should just wait for answers sometimes.)

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?

That would be a large change in the existing behavior, since we only have the (potentially lossy) init(_:) today. It would also be something of a surprise to users of C family languages. That’s not to say that it’s necessarily wrong, but it would break a lot of people’s code an expectations, and I was trying to make this proposal fairly benign, with a focus on adding missing features.

Sure, but it's also a surprise when integers don't roundtrip through floats. (See: every JSON-based API which had to add an "id_str" field when their ID numbers got too big.) I'm not entirely certain it's the right move—you're right that people with a C background wouldn't expect it—but silently doing the wrong thing is a bit suspicious in Swift.

···

--
Brent Royal-Gordon
Architechies

Ultimately, we may want to have a finer-grained classification of numeric protocols, but “schoolbook arithmetic” is a pretty reasonable set of operations while we’re picking just one.

– Steve

The only thing I want to add to this fantastic discussion is that, while "schoolbook arithmetic" should have priority above all else, I'm dreaming about using well-designed language features for quaternions, complex math, matrices, and galiois fields. :)

- Will

···

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That’s precisely SignedArithmetic, just under a different name.

– Steve

···

On Apr 15, 2016, at 11:05 AM, Guillaume Lessard via swift-evolution <swift-evolution@swift.org> wrote:

I don’t see why this is needed; there isn't an AdditivelyInvertible protocol

For the Arithmetic protocol how about changing it to:

    protocol Arithmetic {
        func + (lhs: Self, rhs: Self) -> Self
        mutating func += (rhs: Self) -> Self
        ...
    }

That way naming issues are largely avoided, except for `mutating func
negate()` which has no operator and would therefore have to be a normal,
non-operator, func.

···

On Saturday, 16 April 2016, Nicola Salmoria via swift-evolution < swift-evolution@swift.org> wrote:

> Oh, a couple more things I just thought of:
>
> > public protocol Arithmetic: Equatable, IntegerLiteralConvertible {
> If your goals include supporting complex numbers, how is
IntegerLiteralConvertible going to fit in there?
>
> > /// Initialize to zero
> > init()
> 0 is valuable as the additive identity. Should there also be a way to
get 1, the multiplicative identity? If you need both, should these be
static properties instead of initializers?

Interestingly, these two questions are related.

If you expose the multiplicative identity, you automatically expose a
natural way to convert from an integer N: just add `one` to itself N times.
If N is negative, take the opposite.

For complex numbers the multiplicative identity is 1 + 0i, so this means
that Complex(N) = N + 0i.

As an aside, a default generic implementation of IntegerLiteralConvertible
would run in O(log N) steps, using the “double-and-add” algorithm:

Elliptic curve point multiplication - Wikipedia
.
Though I don’t think this is particularly useful for our use case :-)


Nicola

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.

Does Number hew too close to Foundation's NSNumber name?

`Arithmetic` provides a beautiful hook for grammar pedants: as a protocol name it ought to be pronounced as the adjective "arithMEtic" and not the noun "aRITHmetic". Complaining about that sounds like fun to me, but naming the protocol `Arithmetical` would avoid that issue if others disagree.

···

On Apr 14, 2016, at 10:07 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 14, 2016, at 8:34 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

Stephen Canon wrote:

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”.

Dave A. came up with the name, though I think it’s a good one. Number isn’t bad either.

--
Greg Parker gparker@apple.com Runtime Wrangler

I'd like to have something like Summable with 'add', 'adding' and 'zero' being a
separate protocol as well as somthing like Multiplicative with 'multiply',
'multiplied' and 'one' being a separate protocol, because these are universally
interesting for other cases, e.g. Summable would be useful for defining path
lengths in a graph library.

Would you mind adding that to the proposal?

I suspect you may be headed into the realm of
protocols-as-bags-of-syntax.

You say that like it’s a bad thing… Am I missing the point? (NOT a rhetorical question)

Speaking only for myself, I want stuff broken up into many simpler protocols (which `Arithmetic` and such conform to) because there are many algorithms which only require small parts of the larger protocol. What if I wanted to add a function that sums all the elements in a collection?
extension CollectionType where Generator.Element: Arithmetic {
    func sum() -> Generator.Element {
        var s = Generator.Element()
        for e in self {
            s.add(e)
        }
        return s
    }
}

Yeah, it works, but if I want to get the sum of a collection of some custom type, I have to implement *all* of `Arithmetic`, as opposed to just the two parts of it (`init()` and `.add(:)`) that the algorithm actually uses. It’d be both simpler for the users and *more to the point of the function*, if it could be written like this:
extension CollectionType where Generator.Element: Addable { // "Addable" instead of "Arithmetic"
    ... // No change here
}

Now, if Swift allowed you to add protocol conformance to protocols:
protocol Addable {
    ... // Relevant subset of `Arithmetic`
}
#for T in Arithmetic { // "#for" because this is clearly macro-ish, and # seems to be what we've settled on for that
    extension T : Addable {} // Don't need anything here since `Arithmetic` already has everything in `Addable`
}
… then this all becomes a somewhat moot point. If some generic function only needs a subset of a protocol’s functionality, said function’s author could do this “#for T …” song & dance, and their function would be defined with the minimum constraints.

Look at pages 14 and 24 of
<http://www.cs.indiana.edu/pub/techreports/TR638.pdf&gt;—which does the job
right for C++—and you'll see why.

COOL!!! Thanks for posting that, it looks like it’ll be a great read! :-D

- Dave Sweeris

···

On Apr 20, 2016, at 1:15 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Tue Apr 19 2016, Thorsten Seitz <swift-evolution@swift.org> wrote:

Incidentally, if you make pi and e be static members of the type, we should get a pretty fluent style, along the lines of:

  let x = someDouble * 2 * .pi

I agree that there is a concern about deciding “which” constants to include. I’ll let you and the numeric elite figure that out :-)

-Chris

···

On Apr 14, 2016, at 11:01 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 14, 2016, at 9:49 PM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:

On Apr 14, 2016, at 4:55 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Provide basic constants (analogues of C's DBL_MAX, etc.)

Nice, have you considered adding pi/e and other common constants? I’d really really like to see use of M_PI go away… :-)

That’s a reasonable suggestion. I’m not sure if FloatingPoint is the right protocol to attach them to, but I’m not sure that it’s wrong either. I’d be interested to hear arguments from the community either way.

I’m not sure where the right place is either, I just want them :-) Seriously though, the notion of pi seems to make sense for both decimal and binary fp types, it seems base independent.

Hi Erica, thanks for the feedback.

* I do use % for floating point but not as much as I first thought before I started searching through my code after reading your e-mail. But when I do use it, it's nice to have a really familiar symbol rather than a big word. What were the ways that it was used incorrectly? Do you have some examples?

As it happens, I have a rationale sitting around from an earlier (internal) discussion:

Thanks. That makes plenty of sense although I do still think the name is long and hard to discover compared to fmod[1] and %.

I completely agree. I don’t expect the fmod free function to go away anytime soon, FWIW (and I would oppose removing it unless we had a more discoverable name for this method).

* I don't quite get how equatable is going to work. Do you mind explaining that in more detail?

I’m not totally sure what your question is. Are you asking how FloatingPoint will conform to Equatable, or how the Equatable protocol will work?

Given the many words and passionate articles about how difficult it is to perform floating point comparisons,
for example, Comparing Floating Point Numbers, 2012 Edition | Random ASCII – tech blog of Bruce Dawson,
I'm just curious as to what approach you've settled on. The topic has come up on-list quite a few times.

The actual == and != operators should continue to default to exact (IEEE 754) equality. Doing anything else is asking for a lot of trouble when people try to convert algorithms from other languages.

Support for equality and comparison with a tolerance would be a great library feature, but the difficulty is that it’s impossible to provide a solution that’s appropriate for all (or even most) cases. I have a few sketches of things I’d like to do in that direction, but it’s out of scope for Swift 3, considering the subtle numerics *and* library/language design issues involved.

– Steve

···

On Apr 14, 2016, at 10:12 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 14, 2016, at 10:36 PM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:

On Apr 14, 2016, at 6:29 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Are there potential conforming types which aren't Comparable?

Not at present, but I expect there to be in the future. Modular integers and complex numbers come to mind as the most obvious examples.

Ooh, those are great examples. That is definitely the right decision, then.

(One thing I've been vaguely concerned with is dimensional analysis. A
strong type system opens up the possibility of marking numbers with
units, or at least dimensions, so that the type system can catch when
you try to pass a Second<Pound<T>> to a call that's expecting a
Second<Newton<T>>. Doing this properly requires more freedom in the
multiplication and division operators' parameters and return
values—but of course, it also requires higher-kinded types to
construct the right return values, so it's out of reach for Swift 3
anyway.)

/// 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?

I don’t think that it’s a particularly useful error to detect,

Maybe it's just my lack of knowledge, but I feel like, if you are
calling this method, you probably care about getting that payload into
the resulting NaN. Otherwise you would be using the `nan`
property. (There is no `signalingNan` property, but there could be.)

What do people use NaN payloads for? Are there a lot of cases where
the payload is a nice-to-have, but it's okay to destroy or even mangle
it?

Another option: trap the precondition violation only in debug builds.

and different floating point types may differ greatly in what
payloads they support (if any), because they might choose to reserve
those encodings for other purposes.

If the data you can actually get into a NaN varies so much from one
type to another, is this API a useful one to offer on the protocol? Is
it something you can reliably use on "any floating-point type" without
knowing which type it is?

(It also now occurs to me that this might be better off as an initializer: `init(nanWithPayload:signaling:)`.)

Reading these, I find the use of "least" a little bit misleading—it seems like they should be negative.

Magnitudes are strictly positive. In fairness, that may not be immediately obvious to all readers.

It does make sense now that you've said so! It might be a good doc comment note, though.

  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

This seems wildly over-engineered to me personally. Every language
I surveyed provides (a subset of) these quantities as simple scalar
values.

Well, I am rather prone to wild over-engineering. :^)

One place where a range like FloatingPoint.positives would be useful is in random number generation. Suppose you have:

  protocol Randomizer {
    …
    mutating func choice<T: FloatingPoint>(from choices: ClosedRange<T>) -> T
    …
  }

Which lets you say:

  rng.choice(from: 0...1)

It would then be nice to say something like:

  rng.choice(from: Double.positives)
  rng.choice(from: Float.finites)
  // etc.

Of course, the set of ranges useful for that purpose is probably different from these more technical things, so that might not be the best design anyway.

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?

The Swift 2 Comparable documentation is probably overly specific.
The requirement should really be something like a strict total order
on non-exceptional values.

Okay.

(While I was waiting for your reply, I was thinking about a rework of
`Comparable` which had a sort-oriented `totalOrder(_:)` as a
requirement and `isLess(_:)`, `isGreater(_:)`, et. al. which defaulted
to using `totalOrder(_:)`, but could be overridden for types like
FloatingPoint with exceptional values. I should just wait for answers
sometimes.)

We're still interested in doing something like that.

···

on Fri Apr 15 2016, Brent Royal-Gordon <swift-evolution@swift.org> wrote:

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?

That would be a large change in the existing behavior, since we only
have the (potentially lossy) init(_:) today. It would also be
something of a surprise to users of C family languages. That’s not
to say that it’s necessarily wrong, but it would break a lot of
people’s code an expectations, and I was trying to make this
proposal fairly benign, with a focus on adding missing features.

Sure, but it's also a surprise when integers don't roundtrip through
floats. (See: every JSON-based API which had to add an "id_str" field
when their ID numbers got too big.) I'm not entirely certain it's the
right move—you're right that people with a C background wouldn't
expect it—but silently doing the wrong thing is a bit suspicious in
Swift.

--
Dave

“prefix -" works for negate, at least off the top of my head.

I think.

- Dave Sweeris

···

On Apr 16, 2016, at 6:12 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

For the Arithmetic protocol how about changing it to:

    protocol Arithmetic {
        func + (lhs: Self, rhs: Self) -> Self
        mutating func += (rhs: Self) -> Self
        ...
    }

That way naming issues are largely avoided, except for `mutating func negate()` which has no operator and would therefore have to be a normal, non-operator, func.

Stephen Canon wrote:

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”.

Dave A. came up with the name, though I think it’s a good one. Number isn’t bad either.

Does Number hew too close to Foundation's NSNumber name?

`Arithmetic` provides a beautiful hook for grammar pedants: as a
protocol name it ought to be pronounced as the adjective "arithMEtic"

Yes, or for those less excited by the idea, arith-MEH-tic.

and not the noun "aRITHmetic". Complaining about that sounds like fun
to me, but naming the protocol `Arithmetical` would avoid that issue
if others disagree.

Point taken, but... blick.

···

on Mon Apr 18 2016, Greg Parker <swift-evolution@swift.org> wrote:

On Apr 14, 2016, at 10:07 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 14, 2016, at 8:34 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Dave

I'd like to have something like Summable with 'add', 'adding' and 'zero' being a
separate protocol as well as somthing like Multiplicative with 'multiply',
'multiplied' and 'one' being a separate protocol, because these are universally
interesting for other cases, e.g. Summable would be useful for defining path
lengths in a graph library.

Would you mind adding that to the proposal?

I suspect you may be headed into the realm of
protocols-as-bags-of-syntax.

You say that like it’s a bad thing…

Indeed!

Am I missing the point? (NOT a rhetorical question)

I don't know, but I'll try to help answer...

Speaking only for myself, I want stuff broken up into many simpler
protocols (which `Arithmetic` and such conform to) because there are
many algorithms which only require small parts of the larger
protocol. What if I wanted to add a function that sums all the
elements in a collection?

extension CollectionType where Generator.Element: Arithmetic {
    func sum() -> Generator.Element {
        var s = Generator.Element()
        for e in self {
            s.add(e)
        }
        return s
    }
}

Yeah, it works, but if I want to get the sum of a collection of some custom type, I
have to implement *all* of `Arithmetic`, as opposed to just the two
parts of it (`init()` and `.add(:)`) that the algorithm actually
uses. It’d be both simpler for the users and *more to the point of the
function*, if it could be written like this:

extension CollectionType where Generator.Element: Addable { // "Addable" instead of "Arithmetic"
    ... // No change here
}

This method is undocumented. What does it *do*, given an arbitrary
element type conforming to Addable? The answer needs to be a
description of the semantics that doesn't require me to effectively
execute the source of the function in my head. How can I test that the
method does the right thing? To answer these questions, you have to
attach some semantics to Addable so that it's more than a mere bag of
syntax. For example, for the above to produce the usual semantics of
summing, the Element's init() method needs to produce the additive
identity element.

Choosing the granularity of protocols is something of an art. Lots has
been written about generic programming's “requirement minimization
principle,” in which the more requirements you add, the less reusable
algorithms become. Almost nothing has been written about the other side
of the coin, but...

After much googling I came up with a reference to one of Alexander
Stepanov and James Dehnert's early papers on generic programming (it
sometimes amazes me how many of the key insights can only be found in
that early work):

http://www.stepanovpapers.com/DeSt98.pdf

  We call the set of axioms satisfied by a data type and a set of
  operations on it a concept. Examples of concepts might be an integer
  data type with an addition operation satisfying the usual axioms; or a
  list of data objects with a first element, an iterator for traversing
  the list, and a test for identifying the end of the list. **The critical
  insight which produced generic programming is that highly reusable
  components must be programmed assuming a minimal collection of such
  concepts, and that the concepts used must match as wide a variety of
  concrete program structures as possible**. Thus, successful production
  of a generic component is not simply a matter of identifying the
  minimal requirements of an arbitrary type or algorithm – it requires
  identifying the common requirements of a broad collection of similar
  components. The final requirement is that we accomplish this without
  sacrificing performance relative to programming with concrete
  structures. A good generic library becomes a repository of highly
  efficient data structures and algorithms, based on a small number of
  broadly useful concepts, such that a library user can combine them and
  his own components in a wide variety of ways.

(emphasis mine).

I'm not sure I'm adding anything by saying this, but one problem with
creating protocols that satisfy the absolute minimum requirements for a
particular algorithm is that you end up without any meaningful
abstractions.

“*The* critical insight,” wow. And it's so easily overlooked.

HTH,

···

on Wed Apr 20 2016, davesweeris-AT-mac.com wrote:

On Apr 20, 2016, at 1:15 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Tue Apr 19 2016, Thorsten Seitz <swift-evolution@swift.org> wrote:

--
Dave