How can I round up a CGFloat in Swift?
I've tried ceil(CDouble(myCGFloat))
but that only works on iPad Air & iPhone 5S.
When running on another simulated device I get an error saying 'NSNumber' is not a subtype of 'CGFloat'
How can I round up a CGFloat in Swift?
I've tried ceil(CDouble(myCGFloat))
but that only works on iPad Air & iPhone 5S.
When running on another simulated device I get an error saying 'NSNumber' is not a subtype of 'CGFloat'
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
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.
With Swift 3, according to your needs, you may choose one of the 4 following ways to round up a CGFloat
.
FloatingPoint
protocol rounded(_:)
methodFloatingPoint
protocol gives types that conform to it a rounded(_:)
method. rounded(_:)
has the following declaration:
func rounded(_ rule: FloatingPointRoundingRule) -> Self
Returns this value rounded to an integral value using the specified rounding rule.
The Playground 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
ceil(_:)
functionDarwin provides a ceil(_:)
function that has the following declaration:
public func ceil<T : FloatingPoint>(_ x: T) -> T
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
NSDecimalNumber
NSDecimalNumber
offers a verbose but powerful solution for rounding numbers.
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 scale: Int16 = 0
let behavior = NSDecimalNumberHandler(roundingMode: NSDecimalNumber.RoundingMode.up, scale: scale, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)
let roundedValue1 = NSDecimalNumber(value: Double(value1)).rounding(accordingToBehavior: behavior)
let roundedValue2 = NSDecimalNumber(value: Double(value2)).rounding(accordingToBehavior: behavior)
let roundedValue3 = NSDecimalNumber(value: Double(value3)).rounding(accordingToBehavior: behavior)
let roundedValue4 = NSDecimalNumber(value: Double(value4)).rounding(accordingToBehavior: behavior)
let roundedValue5 = NSDecimalNumber(value: Double(value5)).rounding(accordingToBehavior: behavior)
let roundedValue6 = NSDecimalNumber(value: Double(value6)).rounding(accordingToBehavior: behavior)
print(roundedValue1) // prints 0
print(roundedValue2) // prints 0
print(roundedValue3) // prints -1
print(roundedValue4) // prints 1
print(roundedValue5) // prints 1
print(roundedValue6) // prints 1
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")
Building off of holex's answer. I did
func accurateRound(value: Double) -> Int {
var d : Double = value - Double(Int(value))
if d < 0.5 {
return Int(value)
} else {
return Int(value) + 1
}
}
-edit extension edition-
I also recently turned this into an extension for Floats thought I'd share as well :)
extension Float {
func roundToInt() -> Int{
var value = Int(self)
var f = self - Float(value)
if f < 0.5{
return value
} else {
return value + 1
}
}
}
This is makes it so you can just be like
var f : Float = 3.3
f.roundToInt()
from Swift Standard Library you can round it in-place as well:
var value: CGFloat = -5.7
value.round(.up) // -5.0