Round up a CGFloat in Swift
Solution 1:
Update: Apple have now defined some CGFloat-specific versions of common functions like ceil
:
func ceil(x: CGFloat) -> CGFloat
...specifically to cope with the 32/64-bit difference. If you simply use ceil
with a CGFloat argument it should now work on all architectures.
My original answer:
This is pretty horrible, I think, but can anyone think of a better way? #if
doesn't seem to work for CGFLOAT_IS_DOUBLE
; I think you're limited to build configurations, from what I can see in the documentation for conditional compilation.
var x = CGFloat(0.5)
#if arch(x86_64) || arch(arm64)
var test = ceil(x)
#else
var test = ceilf(x)
#endif
Solution 2:
With Swift 5, you can choose one of the 3 following paths in order to round up a CGFloat
.
#1. Using CGFloat
's rounded(_:)
method
FloatingPoint
protocol gives types that conform to it a rounded(_:)
method. CGFloat
's rounded(_:)
has the following declaration:
func rounded(_ rule: FloatingPointRoundingRule) -> CGFloat
Returns this value rounded to an integral value using the specified rounding rule.
The Playground sample code below shows how to use rounded(_:)
in order to round up a CGFloat
value:
import CoreGraphics
let value1: CGFloat = -0.4
let value2: CGFloat = -0.5
let value3: CGFloat = -1
let value4: CGFloat = 0.4
let value5: CGFloat = 0.5
let value6: CGFloat = 1
let roundedValue1 = value1.rounded(.up)
let roundedValue2 = value2.rounded(.up)
let roundedValue3 = value3.rounded(.up)
let roundedValue4 = value4.rounded(.up)
let roundedValue5 = value5.rounded(.up)
let roundedValue6 = value6.rounded(.up)
print(roundedValue1) // prints -0.0
print(roundedValue2) // prints -0.0
print(roundedValue3) // prints -1.0
print(roundedValue4) // prints 1.0
print(roundedValue5) // prints 1.0
print(roundedValue6) // prints 1.0
#2. Using ceil(_:)
function
Darwin provides a ceil(_:)
function that has the following declaration:
func ceil<T>(_ x: T) -> T where T : FloatingPoint
The Playground code below shows how to use ceil(_:)
in order to round up a CGFloat
value:
import CoreGraphics
let value1: CGFloat = -0.4
let value2: CGFloat = -0.5
let value3: CGFloat = -1
let value4: CGFloat = 0.4
let value5: CGFloat = 0.5
let value6: CGFloat = 1
let roundedValue1 = ceil(value1)
let roundedValue2 = ceil(value2)
let roundedValue3 = ceil(value3)
let roundedValue4 = ceil(value4)
let roundedValue5 = ceil(value5)
let roundedValue6 = ceil(value6)
print(roundedValue1) // prints -0.0
print(roundedValue2) // prints -0.0
print(roundedValue3) // prints -1.0
print(roundedValue4) // prints 1.0
print(roundedValue5) // prints 1.0
print(roundedValue6) // prints 1.0
#3. Using NumberFormatter
If you want to round up a CGFloat
and format it with style in the same operation, you may use NumberFormatter
.
import Foundation
import CoreGraphics
let value1: CGFloat = -0.4
let value2: CGFloat = -0.5
let value3: CGFloat = -1
let value4: CGFloat = 0.4
let value5: CGFloat = 0.5
let value6: CGFloat = 1
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
formatter.roundingMode = NumberFormatter.RoundingMode.ceiling
formatter.maximumFractionDigits = 0
let roundedValue1 = formatter.string(for: value1)
let roundedValue2 = formatter.string(for: value2)
let roundedValue3 = formatter.string(for: value3)
let roundedValue4 = formatter.string(for: value4)
let roundedValue5 = formatter.string(for: value5)
let roundedValue6 = formatter.string(for: value6)
print(String(describing: roundedValue1)) // prints Optional("-0")
print(String(describing: roundedValue2)) // prints Optional("-0")
print(String(describing: roundedValue3)) // prints Optional("-1")
print(String(describing: roundedValue4)) // prints Optional("1")
print(String(describing: roundedValue5)) // prints Optional("1")
print(String(describing: roundedValue6)) // prints Optional("1")
Solution 3:
Use it on swift 5
let x = 6.5
// Equivalent to the C 'round' function:
print(x.rounded(.toNearestOrAwayFromZero))
// Prints "7.0"
// Equivalent to the C 'trunc' function:
print(x.rounded(.towardZero))
// Prints "6.0"
// Equivalent to the C 'ceil' function:
print(x.rounded(.up))
// Prints "7.0"
// Equivalent to the C 'floor' function:
print(x.rounded(.down))
// Prints "6.0"
Solution 4:
The most correct syntax would probably be:
var f: CGFloat = 2.5
var roundedF = CGFloat(ceil(Double(f)))
To use ceil
I will first make the CGFloat
a Double
and after ceiling, I convert it back to CGFloat
.
That works when CGFloat
is defined either as CFloat
or CDouble
.
You could also define a ceil
for floats (This has been actually implemented in Swift 2):
func ceil(f: CFloat) -> CFloat {
return ceilf(f)
}
Then you will be able to call directly
var roundedF: CGFloat = ceil(f)
while preserving type safety.
I actually believe this should be the solution chosen by Apple, instead of having separate ceil
and ceilf
functions because they don't make sense in Swift.