Swift에서 CGFloat 반올림


78

Swift에서 CGFloat를 어떻게 반올림 할 수 있습니까? 시도 ceil(CDouble(myCGFloat))했지만 iPad Air 및 iPhone 5S에서만 작동합니다.

다른 시뮬레이션 된 장치에서 실행할 때 다음과 같은 오류가 발생합니다. 'NSNumber' is not a subtype of 'CGFloat'


2
iPad Air 및 iPhone 5S에서 작동하는 이유는 CGFloats가 해당 아키텍처에서 64 비트이기 때문이라고 생각합니다. 32 비트 아키텍처에서는 32 비트입니다.
Matt Gibson

난 완전히 스위프트가 나에게 말한다 becaus는 무엇 아무 생각이 없다, 혼동하고있어 floor또는 ceil(나 floorf또는 ceilf...입니다)
마크 리드

2
나는이 얼마 전에 있었는지,하지만 당신은 추가 할 필요가 @MarkReedimport Foundation
이안 월터

일반적인 반올림 예제는 이 답변CGFloat참조하십시오 .
Suragch

답변:


117

업데이트 : 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

4
끔찍하지만 지금까지 최고의 솔루션입니다. 그런데 #if와 if의 차이점은 무엇입니까?
Oskar Persson

4
#if는 조건부 컴파일에 사용됩니다. 유사한 if 문을 사용하면 문제가되는 코드가 여전히 컴파일되고 런타임에 실행되지 않더라도 컴파일 타임 오류가 계속 발생합니다. 이렇게하면 선택한 아키텍처에서 컴파일되지 않는 코드 줄이 실제로 컴파일을 위해 전송되지 않습니다.
Matt Gibson

1
@holex 이것이 빠른 이유입니다. 또한 문제 는 컴파일 타임 문제입니다. 다른 아키텍처에 대해 컴파일 할 때 CGFloat가 다르게 정의되기 때문입니다.
Matt Gibson

1
(개인적으로는 더 많은 솔루션을 가진 사람들을 끌어 들이기 위해이 질문이 오랫동안 열려있는 것을 기꺼이 보았을 것입니다. 즉시 중복으로 표시되지 않도록 다시 질문 할 수 있는지 궁금합니다 ... )
Matt Gibson

2
@holex : 컴파일 된 바이너리에서 CGFloat가 float인지 double인지는 컴파일 타임에 완전히 결정됩니다 . 32 비트 바이너리 (32 비트 및 64 비트 하드웨어에서 실행 가능)에서 CGFloat는 부동 소수점입니다. 64 비트 바이너리 (64 비트 하드웨어에서만 실행할 수 있음)에서 CGFloat는 double입니다. - 유니버설 바이너리는 32 비트 및 64 비트 이진 모두 포함하며, 하드웨어에 대한 가장 적절한 픽업 런타임시 실행한다. -따라서이 질문 (ceil () 또는 ceilf () 호출 여부)에 대해서는 코드가 32 비트 또는 64 비트로 컴파일 된 경우에만 관련이 있습니다.
Martin 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(_:)기능 사용

Darwinceil(_:)다음 선언이 있는 함수를 제공합니다 .

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

아래의 플레이 그라운드 코드 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

#삼. 사용NumberFormatter

CGFloat동일한 작업에서 a를 반올림하고 스타일로 서식을 지정하려면 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.

CGFloatCFloat또는 로 정의 될 때 작동합니다 CDouble.

ceilfor floats ( 이것은 실제로 Swift 2에서 구현되었습니다) 를 정의 할 수도 있습니다 .

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

그러면 직접 전화 할 수 있습니다.

var roundedF: CGFloat = ceil(f)

형식 안전성을 유지하면서

사실이 대신 별도의 필요없이 애플이 선택한 해결책이 될 것으로 판단 ceil하고 ceilf그들이 스위프트에 맞지 않는 것들 때문에 기능.


작동하지만 Matt의 솔루션이 더 빠른 것 같습니다. 더 지저분하지만 빠릅니다.
Oskar Persson

@Oskar 두 번째 솔루션을 확인하십시오.
Sulthan 2014-06-12

두 번째 솔루션을 사용하면 여전히 오류 메시지가 나타납니다.'NSNumber' is not a subtype of 'CGFloat'
Oskar Persson

1
이 (설탄의 첫 번째 공식)이 정답입니다. 왜 받아 들여지지 않는지 모르겠습니다. 나는 정확히 동일한 공식을 (독립적으로) 여기에 제공합니다 : stackoverflow.com/a/24186312/341994 이것이 왜 "지저분한 지", 그리고 Matt Gibson의 대답보다 더 지저분한 이유는 확실하지 않습니다. 사실 지저분한 것은 Swift라는 것입니다. 이 중 어느 것도 필요하지 않습니다. 숫자 유형의 지능적인 자동 캐스팅이 필요합니다. 여러분, 파일 개선 요청.
matt 14

1
귀하의 솔루션을 CGFloat의 확장에 넣었습니다. 잘 했어요! extension CGFloat {func roundDown ()-> CGFloat {return CGFloat (floor (Double (self)))} func roundUp ()-> CGFloat {return CGFloat (ceil (Double (self)))}} 이제 myFloat를 호출 할 수 있습니다. .roundDown () 또는 myFloat.roundUp ()! 고마워
토마스 Calmon

12

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"

7

에서 스위프트 표준 라이브러리 는 자리에서 그것을 모아뿐만 아니라 수 있습니다 :

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

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

당신이 완전히 옳습니다. 나는 첫 번째 지점을 수정했습니다.
holex

주어진 CGFloat -5.7에서 소수점 값 0.7을 얻는 방법은 무엇입니까?
kiran

나 같은 공식을 제공하기를 원 (-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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.