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

Xiaodi Wu xiaodi.wu at gmail.com
Fri Apr 22 10:02:32 CDT 2016


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