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

Xiaodi Wu xiaodi.wu at gmail.com
Fri Apr 22 10:16:42 CDT 2016


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