Swift 3 & 4 - making use of the rounded(_:)
method as blueprinted in the FloatingPoint
protocol
The FloatingPoint
protocol (to which e.g. Double
and Float
conforms) blueprints the rounded(_:)
method
func rounded(_ rule: FloatingPointRoundingRule) -> Self
Where FloatingPointRoundingRule
is an enum enumerating a number of different rounding rules:
case awayFromZero
Round to the closest allowed value whose magnitude is greater than or
equal to that of the source.
case down
Round to the closest allowed value that is less than or equal to the
source.
case toNearestOrAwayFromZero
Round to the closest allowed value; if two values are equally close,
the one with greater magnitude is chosen.
case toNearestOrEven
Round to the closest allowed value; if two values are equally close,
the even one is chosen.
case towardZero
Round to the closest allowed value whose magnitude is less than or
equal to that of the source.
case up
Round to the closest allowed value that is greater than or equal to
the source.
We make use of similar examples to the ones from @Suragch's excellent answer to show these different rounding options in practice.
.awayFromZero
Round to the closest allowed value whose magnitude is greater than or equal to that of the source; no direct equivalent among the C functions, as this uses, conditionally on sign of self
, ceil
or floor
, for positive and negative values of self
, respectively.
3.000.rounded(.awayFromZero) // 3.0
3.001.rounded(.awayFromZero) // 4.0
3.999.rounded(.awayFromZero) // 4.0
(-3.000).rounded(.awayFromZero) // -3.0
(-3.001).rounded(.awayFromZero) // -4.0
(-3.999).rounded(.awayFromZero) // -4.0
.down
Equivalent to the C floor
function.
3.000.rounded(.down) // 3.0
3.001.rounded(.down) // 3.0
3.999.rounded(.down) // 3.0
(-3.000).rounded(.down) // -3.0
(-3.001).rounded(.down) // -4.0
(-3.999).rounded(.down) // -4.0
.toNearestOrAwayFromZero
Equivalent to the C round
function.
3.000.rounded(.toNearestOrAwayFromZero) // 3.0
3.001.rounded(.toNearestOrAwayFromZero) // 3.0
3.499.rounded(.toNearestOrAwayFromZero) // 3.0
3.500.rounded(.toNearestOrAwayFromZero) // 4.0
3.999.rounded(.toNearestOrAwayFromZero) // 4.0
(-3.000).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.001).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.499).rounded(.toNearestOrAwayFromZero) // -3.0
(-3.500).rounded(.toNearestOrAwayFromZero) // -4.0
(-3.999).rounded(.toNearestOrAwayFromZero) // -4.0
This rounding rule can also be accessed using the zero argument rounded()
method.
3.000.rounded() // 3.0
// ...
(-3.000).rounded() // -3.0
// ...
.toNearestOrEven
Round to the closest allowed value; if two values are equally close, the even one is chosen; equivalent to the C rint
(/very similar to nearbyint
) function.
3.499.rounded(.toNearestOrEven) // 3.0
3.500.rounded(.toNearestOrEven) // 4.0 (up to even)
3.501.rounded(.toNearestOrEven) // 4.0
4.499.rounded(.toNearestOrEven) // 4.0
4.500.rounded(.toNearestOrEven) // 4.0 (down to even)
4.501.rounded(.toNearestOrEven) // 5.0 (up to nearest)
.towardZero
Equivalent to the C trunc
function.
3.000.rounded(.towardZero) // 3.0
3.001.rounded(.towardZero) // 3.0
3.999.rounded(.towardZero) // 3.0
(-3.000).rounded(.towardZero) // 3.0
(-3.001).rounded(.towardZero) // 3.0
(-3.999).rounded(.towardZero) // 3.0
If the purpose of the rounding is to prepare to work with an integer (e.g. using Int
by FloatPoint
initialization after rounding), we might simply make use of the fact that when initializing an Int
using a Double
(or Float
etc), the decimal part will be truncated away.
Int(3.000) // 3
Int(3.001) // 3
Int(3.999) // 3
Int(-3.000) // -3
Int(-3.001) // -3
Int(-3.999) // -3
.up
Equivalent to the C ceil
function.
3.000.rounded(.up) // 3.0
3.001.rounded(.up) // 4.0
3.999.rounded(.up) // 4.0
(-3.000).rounded(.up) // 3.0
(-3.001).rounded(.up) // 3.0
(-3.999).rounded(.up) // 3.0
Addendum: visiting the source code for FloatingPoint
to verify the C functions equivalence to the different FloatingPointRoundingRule
rules
If we'd like, we can take a look at the source code for FloatingPoint
protocol to directly see the C function equivalents to the public FloatingPointRoundingRule
rules.
From swift/stdlib/public/core/FloatingPoint.swift.gyb we see that the default implementation of the rounded(_:)
method makes us of the mutating round(_:)
method:
public func rounded(_ rule: FloatingPointRoundingRule) -> Self {
var lhs = self
lhs.round(rule)
return lhs
}
From swift/stdlib/public/core/FloatingPointTypes.swift.gyb we find the default implementation of round(_:)
, in which the equivalence between the FloatingPointRoundingRule
rules and the C rounding functions is apparent:
public mutating func round(_ rule: FloatingPointRoundingRule) {
switch rule {
case .toNearestOrAwayFromZero:
_value = Builtin.int_round_FPIEEE${bits}(_value)
case .toNearestOrEven:
_value = Builtin.int_rint_FPIEEE${bits}(_value)
case .towardZero:
_value = Builtin.int_trunc_FPIEEE${bits}(_value)
case .awayFromZero:
if sign == .minus {
_value = Builtin.int_floor_FPIEEE${bits}(_value)
}
else {
_value = Builtin.int_ceil_FPIEEE${bits}(_value)
}
case .up:
_value = Builtin.int_ceil_FPIEEE${bits}(_value)
case .down:
_value = Builtin.int_floor_FPIEEE${bits}(_value)
}
}
pow()
unfortunately not available in a playground – Libnah