On Mon, Jun 27, 2016 at 12:23 Stephen Canon via swift-evolution < swift-evolution@swift.org> wrote:
On Jun 27, 2016, at 12:34 PM, Karl <razielim@gmail.com> wrote:
On 27 Jun 2016, at 16:23, Stephen Canon <scanon@apple.com> wrote:
On Jun 25, 2016, at 05:06, Karl via swift-evolution < > swift-evolution@swift.org> wrote:
Proposal: Add integral rounding functions to FloatingPoint · GitHub
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
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution