【问题标题】:Round up a CGFloat in Swift在 Swift 中收集一个 CGFloat
【发布时间】:2014-06-12 10:20:08
【问题描述】:

如何在 Swift 中四舍五入 CGFloat? 我试过ceil(CDouble(myCGFloat)),但这只适用于 iPad Air 和 iPhone 5S。

在另一个模拟设备上运行时,我收到一条错误消息 'NSNumber' is not a subtype of 'CGFloat'

【问题讨论】:

  • 我认为它在 iPad Air 和 iPhone 5S 上工作的原因是因为 CGFloats 在这些架构上是 64 位的;在 32 位架构上,它们是 32 位。
  • 我完全糊涂了,因为 Swift 告诉我它不知道 floorceil(或 floorfceilf)是什么......
  • @MarkReed 我知道这是不久前的事了,但您需要添加import Foundation
  • 有关CGFloat 的一般舍入示例,请参阅this answer

标签: swift rounding cgfloat ceil


【解决方案1】:

更新:Apple 现已定义了一些 CGFloat 特定版本的常用函数,例如 ceil

func ceil(x: CGFloat) -> CGFloat

...专门用于应对 32/64 位差异。如果您只是将 ceil 与 CGFloat 参数一起使用,它现在应该适用于所有架构。

我原来的答案:

我认为这很可怕,但有人能想到更好的方法吗? #if 似乎不适用于 CGFLOAT_IS_DOUBLE;我认为您仅限于构建配置,来自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

【讨论】:

  • 糟糕,但迄今为止最好的解决方案。顺便问一下,#if 和 if 有什么区别?
  • #if 用于条件编译。如果您使用类似的 if 语句,仍然会编译有问题的代码,并且您仍然会收到编译时错误,即使它不会在运行时运行。这样,在所选架构上无法编译的任何代码行都不会实际发送以进行编译。
  • @holex 这就是为什么它很快。此外,problem 是一个编译时问题;这是因为 CGFloat 在针对不同架构进行编译时定义不同。
  • (虽然就个人而言,我很高兴看到这个问题留待更长时间以吸引更多解决方案的人。我想知道我是否可以再问一次,只是在某种程度上没有它立即标记为重复...)
  • @holex: CGFloat 在编译后的二进制文件中是浮点数还是双精度数完全在编译时确定。在 32 位二进制文​​件中(可以在 32 位和 64 位硬件上运行),CGFloat 是一个浮点数。在 64 位二进制文​​件中(只能在 64 位硬件上运行),CGFloat 是一个 double。 - 通用二进制文件包含 32 位和 64 位二进制文​​件,并选择最适合硬件在运行时执行。 - 所以对于这个问题(是否调用 ceil() 或 ceilf())只有当代码编译为 32 位或 64 位时才相关。
【解决方案2】:

在 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(_:)函数

Darwin 提供了一个 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

如果要将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")

【讨论】:

    【解决方案3】:

    在 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"
    

    【讨论】:

    • 感谢您对枚举选择的清晰解释!
    【解决方案4】:

    最正确的语法可能是:

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

    要使用ceil,我将首先将CGFloat 设为Double,然后在上限之后将其转换回CGFloat

    CGFloat 定义为CFloatCDouble 时,此方法有效。

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

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

    然后就可以直接调用了

    var roundedF: CGFloat = ceil(f)
    

    同时保持类型安全。

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

    【讨论】:

    • 有效,但在我看来,马特的解决方案似乎更快。更混乱,但更快。
    • @Oskar 检查第二个解决方案,我刚刚添加了。
    • 使用第二种解决方案我仍然收到错误消息:'NSNumber' is not a subtype of 'CGFloat'
    • 这(Sulthan 的第一个公式)是正确的答案。我不明白为什么它不被接受。我在这里(独立地)给出完全相同的公式:stackoverflow.com/a/24186312/341994 我不明白为什么这是“混乱”,当然也不明白为什么它比马特吉布森的回答更混乱。事实是 Swift 是混乱的。这些都不是必需的;我们需要数字类型的智能自动转换。文件增强请求,大家。
    • 我将您的解决方案放在 CGFloat 的扩展中。工作得很好! extension CGFloat { func roundDown() -> CGFloat { return CGFloat(floor(Double(self))) } func roundUp() -> CGFloat { return CGFloat(ceil(Double(self))) } } 现在,我可以调用 myFloat .roundDown() 或 myFloat.roundUp()!谢谢,伙计
    【解决方案5】:

    来自Swift Standard Library,您也可以将其圆整:

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

    【讨论】:

    • println("\(roundUp(Double(180.0)))") //prints 181, should print 180
    • 你完全正确,我已经更正了第一个分支。
    • 如何从给定的 CGFloat -5.7 得到十进制值 0.7?
    • 你想让我提供一个像(-5.0) - (-5.7) = 0.7 这样的公式吗?
    【解决方案6】:

    以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()
    

    【讨论】:

      【解决方案7】:

      使用rounded 方法。

      演示(swift 5.5.2):

      CGFloat(5.0).rounded(.up) // -> 5
      
      CGFloat(5.1).rounded(.up) // -> 6
      CGFloat(5.2).rounded(.up) // -> 6
      CGFloat(5.3).rounded(.up) // -> 6
      CGFloat(5.4).rounded(.up) // -> 6
      CGFloat(5.5).rounded(.up) // -> 6
      CGFloat(5.6).rounded(.up) // -> 6
      CGFloat(5.7).rounded(.up) // -> 6
      CGFloat(5.8).rounded(.up) // -> 6
      CGFloat(5.9).rounded(.up) // -> 6
      

      【讨论】:

      • 这应该是公认的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-12
      • 2017-04-26
      • 2014-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多