[Proposal] Add floor() and ceiling() functions to FloatingPoint

IMO, this is the most mathematically meaningful and semantically transparent solution. Floor and ceiling might be the popular terms but roundedUp/Down is much cleaner.

···

On 25 Jun 2016, at 20:55, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 25 Jun 2016, at 11:06, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

floor() and ceil(), exactly like C. ceiling() is more descriptive and is a mathematical term of art <http://mathworld.wolfram.com/CeilingFunction.html&gt;\.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming I've often wondered why it can't just be part of a rounding group of methods like so:

  func roundedUp() -> Self { … }
  func roundedUp(withPrecision:Int) -> Self { … }
  func roundedDown() -> Self { … }
  func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor and ceiling surely? I know floor and ceiling are pretty common terms, but they're just a form rounding when it comes down to it.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing
for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are
formally nouns, just like sine, union, etc. So the API guidelines would
recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and
`round`, `formCeiling`, and `formFloor` for the mutating version.

···

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution < swift-evolution@swift.org> wrote:

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution < > swift-evolution@swift.org> wrote:

We don't seem to have a rounded() function either as part of
FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution < > swift-evolution@swift.org> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution < > swift-evolution@swift.org> wrote:

   - floor() and ceil(), exactly like C. ceiling() is more descriptive
   and is a mathematical term of art
   <http://mathworld.wolfram.com/CeilingFunction.html&gt;\.
   - nextIntegralUp() and nextIntegralDown() are more descriptive still,
   but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming
I've often wondered why it can't just be part of a rounding group of
methods like so:

func roundedUp() -> Self { … }
func roundedUp(withPrecision:Int) -> Self { … }
func roundedDown() -> Self { … }
func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor
and ceiling surely? I know floor and ceiling are pretty common terms, but
they're just a form rounding when it comes down to it.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Whatever the naming scheme, I would be hesitant to have the non-mutating versions of floor and ceil have different endings, seeing how connected they are. So:

floor, ceil
floored, ceiled
flooring, ceiling

But not a mix.

···

On 27 Jun 2016, at 07:13, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:
Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are formally nouns, just like sine, union, etc. So the API guidelines would recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and `round`, `formCeiling`, and `formFloor` for the mutating version.

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution <swift-evolution@swift.org> wrote:

We don't seem to have a rounded() function either as part of FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution <swift-evolution@swift.org> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution <swift-evolution@swift.org> wrote:

floor() and ceil(), exactly like C. ceiling() is more descriptive and is a mathematical term of art.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming I've often wondered why it can't just be part of a rounding group of methods like so:

  func roundedUp() -> Self { … }
  func roundedUp(withPrecision:Int) -> Self { … }
  func roundedDown() -> Self { … }
  func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor and ceiling surely? I know floor and ceiling are pretty common terms, but they're just a form rounding when it comes down to it.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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)
  }

···

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 <mailto:scanon@apple.com>> wrote:

On Jun 25, 2016, at 05:06, Karl via swift-evolution <swift-evolution@swift.org <mailto: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.

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?

(-4.5).truncate == -4
(-4.5).roundedDown == -5

···

On Mon, Jun 27, 2016 at 9:34 AM Karl via swift-evolution < swift-evolution@swift.org> 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:

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.

Karl
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Saagar Jha

Seems fine to me. One addition though: some sort of round(withPrecision:
Int)

···

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

--
-Saagar Jha

A question, perhaps Stephen's to answer: apparently IEEE754 defaults to
what we're calling `toNearestOrEven`? Should Swift be using that as the
default as well?

···

On Wed, Jun 29, 2016 at 7:41 PM, Karl Wagner <razielim@gmail.com> wrote:

OK I’ve incorporated those small things and submitted it for review. We’ve
had an initial discussion, incorporated all the feedback, so I think it’s
met the bar for a PR :+1:

Add integral rounding functions to FloatingPoint by karwa · Pull Request #394 · apple/swift-evolution · GitHub

Karl

On 29 Jun 2016, at 20:20, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Jun 29, 2016 at 1:07 PM, Stephen Canon <scanon@apple.com> wrote:

On Jun 29, 2016, at 2:06 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Jun 29, 2016 at 12:12 PM, Stephen Canon via swift-evolution < >> swift-evolution@swift.org> wrote:

On Jun 29, 2016, at 1:10 PM, Matthew Johnson <matthew@anandabits.com> >>> wrote:

My criticism of the 'toNearestOrGreatest' still stands though. I think
this name is misleading given the stated semantics. The name indicates
"greater value" not "greater magnitude" which are opposites in the case of
negative numbers.

Yup, I agree. I think I originally suggested `toNearestTiesAway`. I’m
not tied to that name specifically, but we should be clear that ties go
away from zero, not up.

Agreed; `toNearestOrAwayFromZero` is the most accurate and consistent
description.

Worth noting that since this is the defaulted behavior, we can get away
with a wordy description.

This is really picking nits, but the most common behavior would be best as
the first enum case, no? Maybe go roughly from most-value-preserving to
least-value-preserving, like so:

`enum RoundingRule { case toNearestOrAwayFromZero, toNearestOrEven, up,
down, towardZero }`

– Steve

I disagree: in English, the nouns are floor and ceiling. That's what they should be called.

Completely agree.

···

On Jun 27, 2016, at 1:53 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Jun 27, 2016 at 02:41 David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
Whatever the naming scheme, I would be hesitant to have the non-mutating versions of floor and ceil have different endings, seeing how connected they are. So:

floor, ceil
floored, ceiled
flooring, ceiling

But not a mix.

On 27 Jun 2016, at 07:13, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are formally nouns, just like sine, union, etc. So the API guidelines would recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and `round`, `formCeiling`, and `formFloor` for the mutating version.

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

We don't seem to have a rounded() function either as part of FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

floor() and ceil(), exactly like C. ceiling() is more descriptive and is a mathematical term of art <http://mathworld.wolfram.com/CeilingFunction.html&gt;\.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming I've often wondered why it can't just be part of a rounding group of methods like so:

  func roundedUp() -> Self { … }
  func roundedUp(withPrecision:Int) -> Self { … }
  func roundedDown() -> Self { … }
  func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor and ceiling surely? I know floor and ceiling are pretty common terms, but they're just a form rounding when it comes down to it.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I disagree: in English, the nouns are floor and ceiling. That's what they
should be called.

···

On Mon, Jun 27, 2016 at 02:41 David Hart <david@hartbit.com> wrote:

Whatever the naming scheme, I would be hesitant to have the non-mutating
versions of floor and ceil have different endings, seeing how connected
they are. So:

floor, ceil
floored, ceiled
flooring, ceiling

But not a mix.

On 27 Jun 2016, at 07:13, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing
for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are
formally nouns, just like sine, union, etc. So the API guidelines would
recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and
`round`, `formCeiling`, and `formFloor` for the mutating version.

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution < >> swift-evolution@swift.org> wrote:

We don't seem to have a rounded() function either as part of
FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution < >> swift-evolution@swift.org> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution < >> swift-evolution@swift.org> wrote:

   - floor() and ceil(), exactly like C. ceiling() is more descriptive
   and is a mathematical term of art
   <http://mathworld.wolfram.com/CeilingFunction.html&gt;\.
   - nextIntegralUp() and nextIntegralDown() are more descriptive still,
   but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming
I've often wondered why it can't just be part of a rounding group of
methods like so:

func roundedUp() -> Self { … }
func roundedUp(withPrecision:Int) -> Self { … }
func roundedDown() -> Self { … }
func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor
and ceiling surely? I know floor and ceiling are pretty common terms, but
they're just a form rounding when it comes down to it.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm with those recommending round, rounded, roundUp, roundedUp, roundDown,
roundedDown, with Remy's precision factored in as needed.

This is usually the point where Dave A wanders in and explains how this can all be
implemented by a single FloatingPoint protocol, with built-in properties
and methods across all FP types in order to limit the API surface area that would be
otherwise affected by creating a whole bunch of native stdlib freestanding functions,
even generic ones.

-- E, starting the "Tailor Swift Simply" party

···

On Jun 27, 2016, at 12:53 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

I disagree: in English, the nouns are floor and ceiling. That's what they should be called.
On Mon, Jun 27, 2016 at 02:41 David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
Whatever the naming scheme, I would be hesitant to have the non-mutating versions of floor and ceil have different endings, seeing how connected they are. So:

floor, ceil
floored, ceiled
flooring, ceiling

But not a mix.

On 27 Jun 2016, at 07:13, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are formally nouns, just like sine, union, etc. So the API guidelines would recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and `round`, `formCeiling`, and `formFloor` for the mutating version.

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

We don't seem to have a rounded() function either as part of FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

floor() and ceil(), exactly like C. ceiling() is more descriptive and is a mathematical term of art <http://mathworld.wolfram.com/CeilingFunction.html&gt;\.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming I've often wondered why it can't just be part of a rounding group of methods like so:

  func roundedUp() -> Self { … }
  func roundedUp(withPrecision:Int) -> Self { … }
  func roundedDown() -> Self { … }
  func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor and ceiling surely? I know floor and ceiling are pretty common terms, but they're just a form rounding when it comes down to it.

This is why I suggested roundedDown() and roundedUp() in place of floor() and ceiling(), as the latter are kind of strange terms to fit into Swift, they're not that explanatory to people that don't know them, and rounding up and down with precision greater than zero could also be useful operations. Plus it would group all rounding methods together.

···

On 27 Jun 2016, at 07:55, James Hillhouse <jdhillhouse4@icloud.com> wrote:

On Jun 27, 2016, at 1:53 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I disagree: in English, the nouns are floor and ceiling. That's what they should be called.

Completely agree.

I noted in another post on this thread that this doesn’t actually make any sense for FloatingPoint. I’ll flesh that out here for everyone’s benefit.

When people talk about rounding to some precision, they almost universally mean “some number of decimal digits”. But for binary floating-point types, rounding to any number of decimal digits other than zero doesn’t actually work. E.g.:

  (1.15).round(withPrecision: 1) // returns 1.1

Why do we get 1.1 here instead of the expected 1.2? Because 1.15 is actually 1.149999999999999911182158029987476766109466552734375. For that matter, we haven’t actually succeeded in rounding to one decimal digit; the resulting value isn’t actually 1.1, but rather 1.100000000000000088817841970012523233890533447265625.

For binary floating-point types, the correct way to make rounding to a fixed number of digits behave as expected is to do it *at the point that the value is converted to a String for display, as part of the formatting*, never as a separate operation.

For a hypothetical DecimalFloatingPoint protocol, on the other hand, it would be perfectly reasonable to have the proposed operation:

  func rounded(digits: Int = 0, rule: RoundingRule) -> Self

– Steve

···

On Jun 27, 2016, at 3:34 PM, Saagar Jha <saagarjha28@gmail.com> wrote:

Seems fine to me. One addition though: some sort of round(withPrecision: Int)

That’s a very good point, IMHO.
- Dave Sweeris

···

On Jun 27, 2016, at 2:43 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 27, 2016, at 3:34 PM, Saagar Jha <saagarjha28@gmail.com> wrote:

Seems fine to me. One addition though: some sort of round(withPrecision: Int)

I noted in another post on this thread that this doesn’t actually make any sense for FloatingPoint. I’ll flesh that out here for everyone’s benefit.

When people talk about rounding to some precision, they almost universally mean “some number of decimal digits”. But for binary floating-point types, rounding to any number of decimal digits other than zero doesn’t actually work. E.g.:

  (1.15).round(withPrecision: 1) // returns 1.1

Why do we get 1.1 here instead of the expected 1.2? Because 1.15 is actually 1.149999999999999911182158029987476766109466552734375. For that matter, we haven’t actually succeeded in rounding to one decimal digit; the resulting value isn’t actually 1.1, but rather 1.100000000000000088817841970012523233890533447265625.

For binary floating-point types, the correct way to make rounding to a fixed number of digits behave as expected is to do it *at the point that the value is converted to a String for display, as part of the formatting*, never as a separate operation.

For a hypothetical DecimalFloatingPoint protocol, on the other hand, it would be perfectly reasonable to have the proposed operation:

  func rounded(digits: Int = 0, rule: RoundingRule) -> Self

– Steve
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That’s the default rounding mode for arithmetic operations, but these “roundToIntegral” operations are orthogonal from the dynamic rounding mode or its default.

Schoolbook rounding (ties away from zero) is both most people’s naive expectation, and also matches the behavior of the C/C++ round( ) function. Principle of least surprise makes it the default choice.

– Steve

···

On Jun 30, 2016, at 4:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

A question, perhaps Stephen's to answer: apparently IEEE754 defaults to what we're calling `toNearestOrEven`? Should Swift be using that as the default as well?

On Wed, Jun 29, 2016 at 7:41 PM, Karl Wagner <razielim@gmail.com <mailto:razielim@gmail.com>> wrote:
OK I’ve incorporated those small things and submitted it for review. We’ve had an initial discussion, incorporated all the feedback, so I think it’s met the bar for a PR :+1:

Add integral rounding functions to FloatingPoint by karwa · Pull Request #394 · apple/swift-evolution · GitHub

Karl

On 29 Jun 2016, at 20:20, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Wed, Jun 29, 2016 at 1:07 PM, Stephen Canon <scanon@apple.com <mailto:scanon@apple.com>> wrote:

On Jun 29, 2016, at 2:06 PM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Wed, Jun 29, 2016 at 12:12 PM, Stephen Canon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 29, 2016, at 1:10 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

My criticism of the 'toNearestOrGreatest' still stands though. I think this name is misleading given the stated semantics. The name indicates "greater value" not "greater magnitude" which are opposites in the case of negative numbers.

Yup, I agree. I think I originally suggested `toNearestTiesAway`. I’m not tied to that name specifically, but we should be clear that ties go away from zero, not up.

Agreed; `toNearestOrAwayFromZero` is the most accurate and consistent description.

Worth noting that since this is the defaulted behavior, we can get away with a wordy description.

This is really picking nits, but the most common behavior would be best as the first enum case, no? Maybe go roughly from most-value-preserving to least-value-preserving, like so:

`enum RoundingRule { case toNearestOrAwayFromZero, toNearestOrEven, up, down, towardZero }`

– Steve

Hmm, I think they'd qualify as terms of art; I don't know that rounding to
an arbitrary decimal place would be (although useful) primitive enough that
they should be added in stdlib [also, to genericize over floats and
doubles, how many decimal places could you usefully get?]; and grouping
families of methods by name has been rejected as a criterion for naming,
though obviously it's elegant where possible.

···

On Mon, Jun 27, 2016 at 05:59 Haravikk <swift-evolution@haravikk.me> wrote:

On 27 Jun 2016, at 07:55, James Hillhouse <jdhillhouse4@icloud.com> wrote:

On Jun 27, 2016, at 1:53 AM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

I disagree: in English, the nouns are floor and ceiling. That's what they
should be called.

Completely agree.

This is why I suggested roundedDown() and roundedUp() in place of floor()
and ceiling(), as the latter are kind of strange terms to fit into Swift,
they're not that explanatory to people that don't know them, and rounding
up and down with precision greater than zero could also be useful
operations. Plus it would group all rounding methods together.

Hadn't thought of roundUp/Down. Makes it so obvious. +10

···

On 27 Jun 2016, at 18:32, Erica Sadun <erica@ericasadun.com> wrote:

I'm with those recommending round, rounded, roundUp, roundedUp, roundDown,
roundedDown, with Remy's precision factored in as needed.

This is usually the point where Dave A wanders in and explains how this can all be
implemented by a single FloatingPoint protocol, with built-in properties
and methods across all FP types in order to limit the API surface area that would be
otherwise affected by creating a whole bunch of native stdlib freestanding functions,
even generic ones.

-- E, starting the "Tailor Swift Simply" party

On Jun 27, 2016, at 12:53 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

I disagree: in English, the nouns are floor and ceiling. That's what they should be called.
On Mon, Jun 27, 2016 at 02:41 David Hart <david@hartbit.com> wrote:

Whatever the naming scheme, I would be hesitant to have the non-mutating versions of floor and ceil have different endings, seeing how connected they are. So:

floor, ceil
floored, ceiled
flooring, ceiling

But not a mix.

On 27 Jun 2016, at 07:13, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Jun 27, 2016 at 12:45 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:
Given the API guidelines, it should be

rounded, ceiled, floored

for returning the rounded/ceiled/floored value and

round(), ceil(), floor()

would be the mutating variants. Question is where it's not too confusing for anyone knowing these from another language.

Although colloquially they can be "verbed," ceil[ing] and floor are formally nouns, just like sine, union, etc. So the API guidelines would recommend: `rounded`, `ceiling`, `floor` for the non-mutating version and `round`, `formCeiling`, and `formFloor` for the mutating version.

On Jun 25, 2016, at 9:02 PM, Remy Demarest via swift-evolution <swift-evolution@swift.org> wrote:

We don't seem to have a rounded() function either as part of FloatingPoint, we should probably have these methods in the end:

func rounded() -> Self
func rounded(withPrecision: Int) -> Self

Along with the 4 other methods proposed below.

Le 25 juin 2016 à 11:55, Haravikk via swift-evolution <swift-evolution@swift.org> a écrit :

On 25 Jun 2016, at 11:06, Karl via swift-evolution <swift-evolution@swift.org> wrote:

floor() and ceil(), exactly like C. ceiling() is more descriptive and is a mathematical term of art.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0

I'm in favour of these capabilities being there, but in terms of naming I've often wondered why it can't just be part of a rounding group of methods like so:

  func roundedUp() -> Self { … }
  func roundedUp(withPrecision:Int) -> Self { … }
  func roundedDown() -> Self { … }
  func roundedDown(withPrecision:Int) -> Self { … }

Since the methods with implied precision of zero are equivalent to floor and ceiling surely? I know floor and ceiling are pretty common terms, but they're just a form rounding when it comes down to it.