Skip to content

Instantly share code, notes, and snippets.

@karwa
Last active June 30, 2016 00:33
Show Gist options
  • Save karwa/273db66cd8a5fe2c388ccc7de9c4cf31 to your computer and use it in GitHub Desktop.
Save karwa/273db66cd8a5fe2c388ccc7de9c4cf31 to your computer and use it in GitHub Desktop.
Add integral rounding functions to FloatingPoint

Add integral rounding functions to FloatingPoint

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

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 integral value; if two values are equally close, the one with greater magnitude is chosen.
	case toNearestOrAwayFromZero
	/// The result is the closest representable integral value; if two values are equally close, the even one is chosen.
	case toNearestOrEven
	/// The result is the closest representable integral value greater than or equal to the source.
	case up
	/// The result is the closest representable integral value less than or equal to the source.
	case down
	/// The result is the closest representable integral value whose magnitude is less than or equal to that of the source.
	case towardZero
}
	
protocol FloatingPoint {

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

    /// Mutating form of `rounded`
    mutating func round(_ rule: RoundingRule = toNearestOrAwayFromZero)
}

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

Note: the rounding rules in the RoundingRule enum correspond to those in IEEE 754.

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.

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

Rationale

On [Date], the core team decided to (TBD) this proposal. When the core team makes a decision regarding this proposal, their rationale for the decision will be written here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment