> On Jun 27, 2016, at 12:34 PM, Karl <[email protected]> wrote:
> 
> 
>> On 27 Jun 2016, at 16:23, Stephen Canon <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> 
>>> On Jun 25, 2016, at 05:06, Karl via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>>> Proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31 
>>>> <https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31>
>> Karl, thanks for writing this up.  It should be extended to include not only 
>> floor( ) and ceiling( ), but also:
>> 
>>      /// Returns the integral value closest to `self` whose magnitude is not 
>> greater than that of `self`.
>>      func truncate( ) -> Self
>> 
>>      /// Returns the integral value closest to `self`.  If two integrers are 
>> equally close, the even one
>>      /// is returned.
>>      //  NOTE: The name of this function requires bike-shedding.  I’ve 
>> chosen a deliberately poor
>>      //  name as a straw-man.
>>      func roundToNearestTiesToEven( ) -> Self
>> 
>>      /// Returns the integral value closest to `self`.  If two integrers are 
>> equally close, the one with
>>      /// greater magnitude is returned.
>>      //  NOTE: The name of this function requires bike-shedding.  I’ve 
>> chosen a deliberately poor
>>      //  name as a straw-man.
>>      func roundToNearestTiesAway( ) -> Self
>> 
>> and mutating versions of those.
>> 
> 
> I was trying to add these, but working out the names of the mutating 
> functions is difficult. How is truncate different to floor if it returns an 
> integral value and can never round up?
> 
> Perhaps for the other functions, we could have a general `round` function 
> with a tiebreak-enum parameter (it would be great if we could embed enums in 
> protocols, but I’m not sure if that’s even on the roadmap):
> 
> enum FloatingPointRoundingStrategy {   // or something to that effect
>     case preferEven
>     case preferGreatest
> }
> 
> func rounded(inTiebreak: FloatingPointRoundingStrategy) -> Self
> 
> I think `(4.5).rounded(inTiebreak: .preferGreatest) == 5.0` looks quite nice.

Yes, something along these lines might work, though 
`FloatingPointRoundingStrategy` isn’t quite right; after all, 
round-towards-infinity (aka ceiling) is also a rounding strategy.

One option (which I don’t totally love, but which simplifies the API surface 
quite a bit, and avoids adding more formXXXX constructions) would be to fold 
all the rounding rules into a single member function (very strawman):

        /// Describes a rule for rounding to an integral value.
        enum RoundingRule {
                /// The result is the closest representable value greater than 
or equal to the source.
                case upwards
                /// The result is the closest representable value less than or 
equal to the source.
                case downwards
                /// The result is the closest representable value whose 
magnitude is less than or equal to that of the source.
                case towardZero
                /// The result is the closest representable value; if two 
values are equally close, the even one is chosen.
                case toNearestTiesToEven
                /// The result is the closest representable value; if two 
values are equally close, the one with greater magnitude is chosen.
                case toNearestTiesAway
        }

        /// Rounds to an integral value according to the specified rounding 
rule.
        mutating func round(_ rule: RoundingRule = toNearestTiesAway)

        func rounded(_ rule: RoundingRule = toNearestTiesAway) -> Self

That gives us e.g.:

        let x = -2.5
        x.round(.upwards)       // -2
        x.round(.downwards)     // -3
        x.round(.towardZero)    // -2
        x.round(.toNearestTiesToEven)   // -2
        x.round()       // -3

We might also provide free functions that implement the most common operations 
under the familiar libc names (I realize that free-functions are not broadly 
considered “swifty”, but they may be appropriate here; we would effectively 
simply be moving these free functions from Darwin/Glibc into the stdlib, and 
making them available for all FloatingPoint types).

        func ceil<T: FloatingPoint>(_ x: T) -> T {
                return x.rounded(.upwards)
        }

        func floor<T: FloatingPoint>(_ x: T) -> T {
                return x.rounded(.downwards)
        }

        func trunc<T: FloatingPoint>(_ x: T) -> T {
                return x.rounded(.towardZero)
        }


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to