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

Stephen Canon scanon at apple.com
Fri Apr 22 09:13:41 CDT 2016


> 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 <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 <https://swift.org/documentation/api-design-guidelines/#strive-for-fluent-usage>.”)
> 
> 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.

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 <https://swift.org/documentation/api-design-guidelines/#general-conventions> 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160422/6d6e76b6/attachment.html>


More information about the swift-evolution mailing list