[swift-evolution] [swift-evolution-announce] [Review] SE-0067: Enhanced Floating Point Protocols

Stephen Canon scanon at apple.com
Fri Apr 22 10:18:51 CDT 2016


It was originally used for nan static function payload argument, but as that function has been removed from the FloatingPoint protocol, the associatedtype could also be moved down.

– Steve

> On Apr 22, 2016, at 11:16 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> 
> One more stray thought:
> Is there a reason RawSignificand is declared in FloatingPoint but used
> only in BinaryFloatingPoint?
> 
> 
> On Fri, Apr 22, 2016 at 10:02 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>> Two stray thoughts:
>> 
>> I agree with previous comments that `ulpOfOne` may not really be necessary.
>> 
>> Of the following--
>> ```
>>  init(signBit: Bool, exponent: Int, significand: Self)
>>  init(magnitudeOf other: Self, signOf: Self)
>> ```
>> --would it be more elegant to have the latter be `init(signOf: Self,
>> magnitudeOf other: Self)`?
>> 
>> 
>> On Fri, Apr 22, 2016 at 9:54 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>> On Fri, Apr 22, 2016 at 9:13 AM, Stephen Canon via swift-evolution
>>> <swift-evolution at swift.org> wrote:
>>>> 
>>>> On Apr 21, 2016, at 9:13 PM, Jordan Rose <jordan_rose at apple.com> wrote:
>>>> 
>>>> [Proposal:
>>>> https://github.com/apple/swift-evolution/blob/master/proposals/0067-floating-point-protocols.md]
>>>> 
>>>> This is super impressive. I do have several bits I’m uncomfortable with,
>>>> however. I’ll try to separate that into “semantic” and “naming” sections.
>>>> 
>>>> Semantic
>>>> 
>>>> static var radix: Int { get }
>>>> 
>>>> 
>>>> Does it ever make sense to have a model type that allows different instances
>>>> to have different radices?
>>>> 
>>>> 
>>>> No.
>>>> 
>>>> Is there an algorithm that makes use of a model’s radix, or is this just in
>>>> here for “completeness”?
>>>> 
>>>> 
>>>> If you know ulp, radix, and exponent range, you can infer basically all the
>>>> other numerical details of the type.  One good example would be the constant
>>>> that Dave mentioned, “maxResultOfAdding1”.  You can compute this if you know
>>>> radix and ulp.  The radix is also the bound on how large the relative
>>>> spacing between consecutive numbers can get, which is sometimes important
>>>> for computing accurate bounds.  These are all somewhat niche, but the
>>>> problem is that there’s no good way to get this value if you don’t have it,
>>>> and it imposes “zero” implementation burden.
>>>> 
>>>>  /// A signaling NaN (not-a-number).
>>>>  @warn_unused_result
>>>>  static func signalingNaN: Self { get }
>>>> 
>>>> 
>>>> I’m not sure it really makes sense for a Bignum / APFloat type to support
>>>> such a value. But really I think this is just underspecified. What does it
>>>> mean, in terms of this protocol and its uses, for a NaN to be signaling? Is
>>>> it just a specific “color" of NaN, with no semantic requirements other than
>>>> being distinguishable?
>>>> 
>>>> 
>>>> There are a variety of means that a softfloat type could use to implement
>>>> signaling NaNs.  Here are two of the simpler ones:
>>>> 
>>>> (a) if running on HW with hard-float support, use native-precision
>>>> hard-float instructions to set flags as needed.
>>>> (b) provide operation variants that take an inout flags / parameter:
>>>> 
>>>> mutating func add(rhs: Self, inout flags: Flags)
>>>> 
>>>> (Also, is ‘signalingNan.isNan’ true? I assume so but since ’nan’ is implied
>>>> to be a non-signaling NaN I’m not sure anymore.)
>>>> 
>>>> 
>>>> Yup, that should be clarified.
>>>> 
>>>>  var signBit: Bool { get }
>>>> 
>>>> 
>>>> Unlike Chris, I’m strongly against this property as it stands. You should
>>>> not be able to write “if someValue.signBit”; a bit is not a boolean value.
>>>> (Citation: "Uses of Boolean methods and properties should read as assertions
>>>> about the receiver.”)
>>>> 
>>>> I’d be okay with Greg’s idea of changing the type to an enum. I’d also be
>>>> okay with renaming this to a predicate, whatever the name ends up being.
>>>> (“isSignBitSet”, “isSignNegative”, etc.)
>>>> 
>>>> 
>>>> Making it a predicate is weird, because then the three properties making up
>>>> the number become `isSignBitSet`, `exponent`, and `significand`; one of
>>>> these things is not like the other ones.  If `signBit: Bool` were ruled out,
>>>> I would rather go with Greg’s enum proposal.
>>>> 
>>>>  var exponent: Int { get }
>>>> 
>>>> 
>>>> Nitpick: it’s probably worth noting in the doc comment that this is the
>>>> unbiased exponent value.
>>>> 
>>>> Also, does it matter that this is insufficient for bignums, which may have
>>>> an exponent of greater than `sizeof(Int.self)` bits? (This is also a concern
>>>> for a number of members of BinaryFloatingPoint, like ‘significantBitCount’.)
>>>> 
>>>> 
>>>> An exponent of Int.max encodes a number >= 2**Int.max.  This is a
>>>> staggeringly huge quantity, even when Int is 32 bits (it’s approximately
>>>> 1e646456992).  There are a few extremely niche applications that require
>>>> numbers with greater magnitude, but they are *extremely* rare.  To a good
>>>> approximation, `Int` is more than enough bits, and a reasonable tradeoff.
>>> 
>>> Naive question: is it necessary to make a trade-off here? Why not an
>>> associated type Exponent that's Int for Float, Double, and Float80,
>>> allowing for something else for bignums?
>>> 
>>>> Ditto `significandBitCount`.  I haven’t seen usage of floating-point types
>>>> with more than a few thousand significand bits; billions of bits is enough.
>>>> It is plausible that one could build a type that runs into this limit on a
>>>> 32-bit system, but it wouldn’t be very useful; on a 64-bit system, you can’t
>>>> allocate the storage for even one such value.
>>>> 
>>>> Naming
>>>> 
>>>> On “NaN” vs. “Nan”: I’m not convinced that ignoring the case is the right
>>>> way to go here. IMHO the clearest lowercase form is “nan” and the clearest
>>>> capitalized form is “NaN”.
>>>> 
>>>> The current draft API guidelines don’t cover this case, but if I were to add
>>>> something for this, I’d say “when a word is normally written with mixed
>>>> case, the lowercase form should be fully-lowercased if the first letter is
>>>> naturally uppercase, and the capitalized form should have the first letter
>>>> uppercased only.” That rule produces “iPhone/IPhone”, “next/NeXT”, and
>>>> “nan/NaN”. (The “if the first letter is naturally uppercase” could be thrown
>>>> out as well.)
>>>> 
>>>> 
>>>> Yup, this seems like a sensible rule to me.
>>>> 
>>>> On 'isLessThanOrEqual(to:)’: I agree with Xiaodi that the argument label is
>>>> problematic here. I think the problem is that we have two prepositions that
>>>> apply to the argument, and “pick the second one” leaves the base name
>>>> feeling unbalanced. (Remember that we allow referring to a method by its
>>>> basename alone when using it as a function value.)
>>>> 
>>>> On 'isTotallyOrdered(with:)’: I lost track of who said it, but I agree that
>>>> this sounds like it’s “!isUnordered(with: other)”. The only name that’s
>>>> coming to mind is ‘isTotallyOrderedBefore(_:)’, which isn’t great.
>>>> 
>>>> On ‘binade’: At first I thought this was a confusing term and there had to
>>>> be a better one, but now I think it’s an “if you don’t know what this is,
>>>> you don’t need to use it” case. :-)
>>>> 
>>>> 
>>>> Yup.
>>>> 
>>>> – Steve
>>>> 
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> 



More information about the swift-evolution mailing list