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
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")
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.
from Swift Standard Library you can round it in-place as well:
var value: CGFloat = -5.7
value.round(.up) // -5.0
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()
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"
来源:https://stackoverflow.com/questions/24181992/round-up-a-cgfloat-in-swift