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


(Karl) #1

Proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31

Introduction, Motivation

The standard library lacks equivalents to the floor() and ceil() functions found in the standard libraries of most other languages. Currently, we need to import Darwin or Glibc in order to access the C standard library versions.

They are essential for many algorithms, and adding them would allow more basic algorithms to be written platform-independently (or at least without #if (os) flags at the top).

<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#proposed-solution>Proposed Solution

Add floor and ceiling functions (and mutating variants) to FloatingPoint

protocol FloatingPoint {

    ...

    /// Returns the largest integral value not greater than `self`
    func floor() -> Self
    /// Mutating form of `floor`
    mutating func formFloor()

    /// Returns the smallest integral value not less than `self`
    func ceiling() -> Self
    /// Mutating form of `ceiling`
    mutating func formCeiling()
}
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#impact-on-existing-code>Impact on existing code

This change is additive, although we may consider suppressing the imported, global-level C functions and automatically migrating them to instance method calls.

<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#alternatives-considered>Alternatives considered

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


(David Sweeris) #2

+1

The only thing I'm worried about is the situation where we have "x = N.M", and `x.ceiling` equals maybe "(N+2).0" instead of "(N+1).0" because we ran out of precision and can't represent (N+1).0. I'm not sure what the exact values are where floats (or doubles) stop having enough precision to represent inter-integer values... It might be a moot point.

I'd suggest the functions' descriptions to be changed from "[largest|smallest] integral value" to "[largest|smallest] representable integral value".

- Dave Sweeris

···

Sent from my iPhone

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

Proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31


(Austin Rathe) #3

+1 to the proposal

···

On Sat, 25 Jun 2016 at 17:48 David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPhone
On Jun 25, 2016, at 05:06, Karl via swift-evolution < > swift-evolution@swift.org> wrote:

Proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31

+1

The only thing I'm worried about is the situation where we have "x = N.M",
and `x.ceiling` equals maybe "(N+2).0" instead of "(N+1).0" because we ran
out of precision and can't represent (N+1).0. I'm not sure what the exact
values are where floats (or doubles) stop having enough precision to
represent inter-integer values... It might be a moot point.

I'd suggest the functions' descriptions to be changed from
"[largest|smallest] integral value" to "[largest|smallest] representable
integral value".

- Dave Sweeris

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


(Haravikk) #4

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.

···

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>.
nextIntegralUp() and nextIntegralDown() are more descriptive still, but possibly misleading as (4.0).nextIntegralUp() == 4.0


(Stephen Canon) #5

Proposal: 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.

Some collected responses to other comments on this thread:

David Sweeris wrote:

The only thing I'm worried about is the situation where we have "x = N.M", and `x.ceiling` equals maybe "(N+2).0" instead of "(N+1).0" because we ran out of precision and can't represent (N+1).0. I'm not sure what the exact values are where floats (or doubles) stop having enough precision to represent inter-integer values... It might be a moot point.

This never happens. Floor and ceiling are always exact operations.

Austin Rathe wrote:

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

While I understand where you’re going with this, you can’t round non-decimal floating-point numbers to a non-zero number of decimal digits (the result won’t be representable, in general). This should be available for decimal floating-point types if/when they are added, but should be handled as part of conversions to String for binary floating-point types.

– Steve

···

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


(David Sweeris) #6

I'm starting to come down from me earlier +1... Floor and ceiling are more functions than properties of a number, aren't they?

- Dave Sweeris

···

On Jun 25, 2016, at 11:48, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

+1

The only thing I'm worried about is the situation where we have "x = N.M", and `x.ceiling` equals maybe "(N+2).0" instead of "(N+1).0" because we ran out of precision and can't represent (N+1).0. I'm not sure what the exact values are where floats (or doubles) stop having enough precision to represent inter-integer values... It might be a moot point.

I'd suggest the functions' descriptions to be changed from "[largest|smallest] integral value" to "[largest|smallest] representable integral value".

- Dave Sweeris


(Karl) #7

Updated proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31

Add integral rounding functions to FloatingPoint

Proposal: SE-NNNN <https://gist.github.com/karwa/NNNN-filename.md>
Author: Karl Wagner <https://github.com/karwa>
Status: Awaiting review <https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#rationale>
Review manager: TBD
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#introduction-motivation>Introduction, Motivation

The standard library lacks equivalents to the floor() and ceil() functions found in the standard libraries of most other languages. Currently, we need to import Darwin or Glibc in order to access the C standard library versions.

In general, rounding of floating-point numbers for predictable conversion in to integers is something we should provide natively.

Swift-evolution thread: [Proposal] Add floor() and ceiling() functions to FloatingPoint <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160620/022146.html>
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#proposed-solution>Proposed Solution

The proposed rounding API consists of a RoundingRule enum and new round and rounded methods on FloatingPoint

    /// 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 up
        /// The result is the closest representable value less than or equal to the source.
        case down
        /// 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 toNearestOrEven
        /// The result is the closest representable value; if two values are equally close, the one with greater magnitude is chosen.
        case toNearestOrGreatest
    }

protocol FloatingPoint {

    ...

    /// Returns a rounded representation of `self`, according to the specified rounding rule.
    func rounded(_ rule: RoundingRule = toNearestOrGreatest) -> Self

    /// Mutating form of `rounded`
    mutating func round(_ rule: RoundingRule = toNearestOrGreatest)
}
Calls such as rounded(.up) or rounded(.down) are equivalent to C standard library ceil() and floor() functions.

(4.4).rounded() == 4.0
(4.5).rounded() == 5.0
(4.0).rounded(.up) == 4.0
(4.0).rounded(.down) == 4.0
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#impact-on-existing-code>Impact on existing code

This change is additive, although we may consider suppressing the imported, global-level C functions, or perhaps automatically migrating them to the new instance-method calls.

<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#alternatives-considered>Alternatives considered

floor() and ceiling(). The mailing list discussion indicated more nuanced forms of rounding were desired, and that it would be nice to abandon these technical names for what is a pretty common operation.
floor() and ceil() or ceiling() are mathematical terms of art <http://mathworld.wolfram.com/CeilingFunction.html>. But most people who want to round a floating point are not mathematicians.
nextIntegralUp() and nextIntegralDown() are more descriptive, and perhaps a better fit with the rest of the FloatingPoint API, but possibly misleading as (4.0).nextIntegralUp() == 4.0


(Psycho Hedgehog) #8

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 <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>.
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


(Charlie Monroe) #9

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.

···

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 <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>.
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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Karl) #10

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.

Karl

···

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 <mailto:swift-evolution@swift.org>> wrote:

Proposal: 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.


(Pyry Jahkola) #11

David Sweeris wrote:

I'm starting to come down from me earlier +1... Floor and ceiling are more functions than properties of a number, aren't they?

I agree with that. Having used various math libraries for decades now, I'd find it odd to find these as members of a floating-point type, especially so for the suggested in-place mutating variants. These tend to be function-like constructs (or various kinds of brackets) in mathematics too, just like trigonometric functions.

But since do we need these in the FloatingPoint protocol for generic algorithms, I'd suggest defining them as static members, and keeping state-of-art names (or close) where possible:

    protocol FloatingPoint {
      static func floor(_ value: Self) -> Self
      static func ceiling(_ value: Self) -> Self
      static func truncate(_ value: Self) -> Self
      static func round(_ value: Self) -> Self
    }

The top-level functions can them simply delegate to these counterparts:

    func floor<T : FloatingPoint>(_ value: T) -> T {
      return .floor(value)
    }

— Pyry


(Matthew Johnson) #12

+1 to adding robust rounding to he standard library.

I’m curious why we have both `up` and `down`, but only have `towardZero` without `awayFromZero`.

I’m also curious what the use case is for `toNearestOrEven` and why you don’t include `toNearestOrOdd`.

I think the name of `toNearestOrGreatest` could use improvement. The name doesn’t indicate greatest magnitude and could easily be confused with some `toNearestOrUp` (rounding towards positive infinity). Maybe you should call it `toNearestOrAwayFromZero` (building on the convention implied by `towardZero`). This also raises the question of why we don’t have other similar rules such as `toNearestOrDown` and `toNearestOrTowardZero`.

Maybe there are good reasons for covering a subset of the possible space of rounding rules but not all of it. If there are you should provide rationale in the proposal. If there aren’t, maybe you should consider including the additional options.

-Matthew

···

On Jun 29, 2016, at 11:20 AM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

Updated proposal: https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31

Add integral rounding functions to FloatingPoint

Proposal: SE-NNNN <https://gist.github.com/karwa/NNNN-filename.md>
Author: Karl Wagner <https://github.com/karwa>
Status: Awaiting review <https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#rationale>
Review manager: TBD
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#introduction-motivation>Introduction, Motivation

The standard library lacks equivalents to the floor() and ceil() functions found in the standard libraries of most other languages. Currently, we need to import Darwin or Glibc in order to access the C standard library versions.

In general, rounding of floating-point numbers for predictable conversion in to integers is something we should provide natively.

Swift-evolution thread: [Proposal] Add floor() and ceiling() functions to FloatingPoint <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160620/022146.html>
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#proposed-solution>Proposed Solution

The proposed rounding API consists of a RoundingRule enum and new round and rounded methods on FloatingPoint

    /// 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 up
        /// The result is the closest representable value less than or equal to the source.
        case down
        /// 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 toNearestOrEven
        /// The result is the closest representable value; if two values are equally close, the one with greater magnitude is chosen.
        case toNearestOrGreatest
    }

protocol FloatingPoint {

    ...

    /// Returns a rounded representation of `self`, according to the specified rounding rule.
    func rounded(_ rule: RoundingRule = toNearestOrGreatest) -> Self

    /// Mutating form of `rounded`
    mutating func round(_ rule: RoundingRule = toNearestOrGreatest)
}
Calls such as rounded(.up) or rounded(.down) are equivalent to C standard library ceil() and floor() functions.

(4.4).rounded() == 4.0
(4.5).rounded() == 5.0
(4.0).rounded(.up) == 4.0
(4.0).rounded(.down) == 4.0
<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#impact-on-existing-code>Impact on existing code

This change is additive, although we may consider suppressing the imported, global-level C functions, or perhaps automatically migrating them to the new instance-method calls.

<https://gist.github.com/karwa/273db66cd8a5fe2c388ccc7de9c4cf31#alternatives-considered>Alternatives considered

floor() and ceiling(). The mailing list discussion indicated more nuanced forms of rounding were desired, and that it would be nice to abandon these technical names for what is a pretty common operation.
floor() and ceil() or ceiling() are mathematical terms of art <http://mathworld.wolfram.com/CeilingFunction.html>. But most people who want to round a floating point are not mathematicians.
nextIntegralUp() and nextIntegralDown() are more descriptive, and perhaps a better fit with the rest of the FloatingPoint API, but possibly misleading as (4.0).nextIntegralUp() == 4.0

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


(Matthew Johnson) #13

+1 to adding robust rounding to he standard library.

I’m curious why we have both `up` and `down`, but only have `towardZero` without `awayFromZero`.

I’m also curious what the use case is for `toNearestOrEven` and why you don’t include `toNearestOrOdd`.

I think the name of `toNearestOrGreatest` could use improvement. The name doesn’t indicate greatest magnitude and could easily be confused with some `toNearestOrUp` (rounding towards positive infinity). Maybe you should call it `toNearestOrAwayFromZero` (building on the convention implied by `towardZero`). This also raises the question of why we don’t have other similar rules such as `toNearestOrDown` and `toNearestOrTowardZero`.

Maybe there are good reasons for covering a subset of the possible space of rounding rules but not all of it. If there are you should provide rationale in the proposal. If there aren’t, maybe you should consider including the additional options.

The rounding rules in the proposal are precisely the rounding rules required by IEEE 754. Not coincidentally, these are also the rounding rules that have fast hardware support for concrete types on common architectures, and the rounding rules that software expects to be able to use.

I was guessing there was a rationale like this that I wasn't aware of. :). Thanks for providing it! That's all I was looking for. I do think it would be a good idea to add it to the proposal.

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.

···

Sent from my iPhone

On Jun 29, 2016, at 12:00 PM, Stephen Canon <scanon@apple.com> wrote:

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

Of your suggestions for symmetry, I’ve only ever seen `awayFromZero` used (e.g. I’ve never seen anyone use `toNearestOrOdd`). If we did want to extend the set of IEEE 754 rounding rules, I would add the following two rules:

/// The result is the closest representable value whose magnitude is greater than or equal to that of the source.
// Rationale: it’s actually used, though not as frequently as the operations in the proposal.
case awayFromZero

/// If the source is not exactly representable, the result is the closest odd number.
// Rationale: although this is mostly useless for rounding-to-integer, it’s an extremely useful rounding rule to have for *other* floating-point operations, so if we’re going to extend the set, it makes sense to add it.
case toOdd

I have never seen a use case that would require extending the set any further than that.

The thing that would actually be extremely useful is support for dithered or stochastic rounding, but that’s a can of API design worms that’s out of scope for Swift 3; you need to be able to describe not just the rule, but also a noise source and shape / spectrum.

– Steve


(Stephen Canon) #14

The rounding rules in the proposal are precisely the rounding rules required by IEEE 754. Not coincidentally, these are also the rounding rules that have fast hardware support for concrete types on common architectures, and the rounding rules that software expects to be able to use.

Of your suggestions for symmetry, I’ve only ever seen `awayFromZero` used (e.g. I’ve never seen anyone use `toNearestOrOdd`). If we did want to extend the set of IEEE 754 rounding rules, I would add the following two rules:

/// The result is the closest representable value whose magnitude is greater than or equal to that of the source.
// Rationale: it’s actually used, though not as frequently as the operations in the proposal.
case awayFromZero

/// If the source is not exactly representable, the result is the closest odd number.
// Rationale: although this is mostly useless for rounding-to-integer, it’s an extremely useful rounding rule to have for *other* floating-point operations, so if we’re going to extend the set, it makes sense to add it.
case toOdd

I have never seen a use case that would require extending the set any further than that.

The thing that would actually be extremely useful is support for dithered or stochastic rounding, but that’s a can of API design worms that’s out of scope for Swift 3; you need to be able to describe not just the rule, but also a noise source and shape / spectrum.

– Steve

···

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

+1 to adding robust rounding to he standard library.

I’m curious why we have both `up` and `down`, but only have `towardZero` without `awayFromZero`.

I’m also curious what the use case is for `toNearestOrEven` and why you don’t include `toNearestOrOdd`.

I think the name of `toNearestOrGreatest` could use improvement. The name doesn’t indicate greatest magnitude and could easily be confused with some `toNearestOrUp` (rounding towards positive infinity). Maybe you should call it `toNearestOrAwayFromZero` (building on the convention implied by `towardZero`). This also raises the question of why we don’t have other similar rules such as `toNearestOrDown` and `toNearestOrTowardZero`.

Maybe there are good reasons for covering a subset of the possible space of rounding rules but not all of it. If there are you should provide rationale in the proposal. If there aren’t, maybe you should consider including the additional options.


(Stephen Canon) #15

(N.B. My recommendation is to *not* add any of these alternative modes at this point in time. Let’s keep this small so that we can get it wrapped up as quickly as possible).

···

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

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

+1 to adding robust rounding to he standard library.

I’m curious why we have both `up` and `down`, but only have `towardZero` without `awayFromZero`.

I’m also curious what the use case is for `toNearestOrEven` and why you don’t include `toNearestOrOdd`.

I think the name of `toNearestOrGreatest` could use improvement. The name doesn’t indicate greatest magnitude and could easily be confused with some `toNearestOrUp` (rounding towards positive infinity). Maybe you should call it `toNearestOrAwayFromZero` (building on the convention implied by `towardZero`). This also raises the question of why we don’t have other similar rules such as `toNearestOrDown` and `toNearestOrTowardZero`.

Maybe there are good reasons for covering a subset of the possible space of rounding rules but not all of it. If there are you should provide rationale in the proposal. If there aren’t, maybe you should consider including the additional options.

The rounding rules in the proposal are precisely the rounding rules required by IEEE 754. Not coincidentally, these are also the rounding rules that have fast hardware support for concrete types on common architectures, and the rounding rules that software expects to be able to use.

Of your suggestions for symmetry, I’ve only ever seen `awayFromZero` used (e.g. I’ve never seen anyone use `toNearestOrOdd`). If we did want to extend the set of IEEE 754 rounding rules, I would add the following two rules:

/// The result is the closest representable value whose magnitude is greater than or equal to that of the source.
// Rationale: it’s actually used, though not as frequently as the operations in the proposal.
case awayFromZero

/// If the source is not exactly representable, the result is the closest odd number.
// Rationale: although this is mostly useless for rounding-to-integer, it’s an extremely useful rounding rule to have for *other* floating-point operations, so if we’re going to extend the set, it makes sense to add it.
case toOdd

I have never seen a use case that would require extending the set any further than that.

The thing that would actually be extremely useful is support for dithered or stochastic rounding, but that’s a can of API design worms that’s out of scope for Swift 3; you need to be able to describe not just the rule, but also a noise source and shape / spectrum.


(Xiaodi Wu) #16

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.

···

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:

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


(Stephen Canon) #17

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.

···

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.


(Xiaodi Wu) #18

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

···

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:

– Steve


(Stephen Canon) #19

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

– Steve

···

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 <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.


(Karl) #20

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:

https://github.com/apple/swift-evolution/pull/394

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