在Swift中汇总CGFloat


78

如何在Swift中汇总CGFloat?我已经尝试过了,ceil(CDouble(myCGFloat))但是只能在iPad Air和iPhone 5S上使用。

在另一台模拟设备上运行时,出现错误提示 'NSNumber' is not a subtype of 'CGFloat'


2
我认为它可以在iPad Air和iPhone 5S上运行的原因是因为CGFloat在这些体系结构上是64位的。在32位架构上,它们是32位。
Matt Gibson 2014年

我完全糊涂了,斯威夫特因为...告诉我,它不知道floorceil(或floorfceilf)是...
马克·里德

2
@MarkReed我知道这是前一段时间,但是您需要添加import Foundation
Ian Walter

有关一般的取整示例,CGFloat请参见此答案
Suragch '16

Answers:


116

更新:Apple现在已经定义了一些CGFloat特定版本的常用功能,例如ceil

func ceil(x: CGFloat) -> CGFloat

...专门解决32/64位的差异。如果仅使用ceilCGFloat参数,则它现在应在所有体系结构上都适用。

我的原始答案:

我认为这太可怕了,但是谁能想到更好的方法?#if似乎没有工作CGFLOAT_IS_DOUBLE; 根据我在条件编译文档中看到的内容,我认为您仅限于构建配置。

var x = CGFloat(0.5)

#if arch(x86_64) || arch(arm64)
var test = ceil(x)
#else
var test = ceilf(x)
#endif

3
可怕的是,到目前为止最好的解决方案。顺便说一下,#if和if有什么区别?
Oskar Persson 2014年

4
#if用于条件编译。如果您使用类似的if语句,那么仍将编译有问题的代码,即使它不会在运行时运行,您仍会收到编译时错误。这样,无论哪种代码行都不会在选定的体系结构上进行编译,它实际上都不会发送给编译。
Matt Gibson 2014年

1
@holex这就是为什么它很快的原因。另外,该问题是编译时问题;这是因为在为不同体系结构进行编译时,CGFloat的定义不同。
Matt Gibson 2014年

1
(尽管就我个人而言,我很高兴看到这个问题开放了更长的时间,以吸引更多解决方案的人们。我想知道我是否可以再次提出这个问题,只是以不立即将其标记为重复的方式... )
Matt Gibson 2014年

2
@holex:在编译时完全确定CGFloat在已编译二进制文件中是float还是double 。在32位二进制文​​件(可以在32位和64位硬件上运行)中,CGFloat是浮点数。在64位二进制文​​件(只能在64位硬件上运行)中,CGFloat是两倍。-通用二进制文件同时包含32位和64位二进制文​​件,并在运行时选择最适合硬件的硬件。-因此,对于此问题(无论调用ceil()还是ceilf()),仅当代码编译为32位或64位时才有意义。
马丁R

40

使用Swift 5,您可以选择以下3条路径之一来取整CGFloat


#1 使用CGFloatrounded(_:)方法

FloatingPoint协议给符合它的类型提供一种rounded(_:)方法。CGFloatrounded(_:)具有以下声明:

func rounded(_ rule: FloatingPointRoundingRule) -> CGFloat

使用指定的舍入规则返回将此值舍入为整数值。

下面的Playground示例代码显示了如何使用rounded(_:)它来取整一个CGFloat值:

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。使用ceil(_:)功能

达尔文提供的ceil(_:)函数具有以下声明:

func ceil<T>(_ x: T) -> T where T : FloatingPoint

下面的Playground代码显示了如何使用ceil(_:)来取整一个CGFloat值:

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。使用NumberFormatter

如果您想对a进行四舍五入CGFloat并在同一操作中以样式设置其格式,则可以使用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")

21

最正确的语法可能是:

var f: CGFloat = 2.5
var roundedF = CGFloat(ceil(Double(f)))

要使用该功能,ceil我会先设置CGFloata Double,然后设置上限,然后将其转换回CGFloat

CGFloat定义为CFloat或时有效CDouble

您还可以定义一个ceilfor浮点数(这实际上已在Swift 2中实现):

func ceil(f: CFloat) -> CFloat {
   return ceilf(f)
}

这样您就可以直接致电

var roundedF: CGFloat = ceil(f)

同时保持类型安全。

我实际上认为这应该是Apple选择的解决方案,而不是具有单独的ceilceilf功能,因为它们在Swift中没有意义。


可行,但对我来说,Matt的解决方案似乎更快。更混乱,但速度更快。
Oskar Persson 2014年

@Oskar检查第二个解决方案,我刚刚添加了。
Sulthan 2014年

使用第二个解决方案,我仍然收到错误消息:'NSNumber' is not a subtype of 'CGFloat'
Oskar Persson 2014年

1
这(Sulthan的第一个公式)是正确的答案。我不明白为什么它不是被接受的。我在这里(独立地)给出了完全相同的表述:stackoverflow.com/a/24186312/341994我看不出为什么这是“混乱的”,当然也不是为什么它比Matt Gibson的回答更混乱。事实是,Swift太混乱了。这些都没有必要;我们需要智能的数字类型自动转换。大家都提出文件增强要求。
马特2014年

1
我将您的解决方案放入CGFloat的扩展程序中。做得好!扩展CGFloat {func roundDown()-> CGFloat {return CGFloat(floor(Double(self)))} func roundUp()-> CGFloat {return CGFloat(ceil(Double(self)))}}现在,我可以调用myFloat .roundDown()或myFloat.roundUp()!谢谢,伙计
托马斯·卡尔蒙

12

快速使用它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"

7

Swift标准库中,您也可以将其四舍五入:

var value: CGFloat = -5.7
value.round(.up) // -5.0

1
println("\(roundUp(Double(180.0)))") //prints 181, should print 180
Oskar Persson 2014年

您完全正确,我已经纠正了第一分支。
Holex 2014年

如何从给定的CGFloat -5.7获取十进制值0.7?
基兰

您要我提供类似的公式(-5.0) - (-5.7) = 0.7吗?
Holex

5

以Holex的答案为基础。我做了

func accurateRound(value: Double) -> Int {

            var d : Double = value - Double(Int(value))

            if d < 0.5 {
                return Int(value)
            } else {
                return Int(value) + 1
            }
        }

-编辑扩展版-

我最近还把它变成了Floats的扩展,以为我也愿意分享:)

extension Float {
    func roundToInt() -> Int{
        var value = Int(self)
        var f = self - Float(value)
        if f < 0.5{
            return value
        } else {
            return value + 1
        }
    }
}

这样就可以使您就像

var f : Float = 3.3
f.roundToInt()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.