Swift - 고급 연산자

임성빈·2022년 4월 28일
0

Swift

목록 보기
26/26
post-thumbnail
post-custom-banner

고급 연산자


비트 연산자

Swift에서도 여러 비트 연산자를 지원한다.

비트 연산자 NOT

비트 연산자 NOT는 비트를 뒤집는다.

let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits
// equals 11110000

비트 연산자 AND

비트 연산자 AND는 두 비트가 같은 값인 경우 1 다른 경우 0으로 반환한다.

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits
// equals 00111100

비트 연산자 OR

비트 연산자 OR은 두 비트 가운데 하나라도 1이면 1 값을 갖는다.

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits
// equals 11111110

비트 연산자 XOR

비트 연산자 XOR은 두 비트가 다른 경우에 1, 같은 경우에 0을 갖는다.

let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits
// equals 00010001

비트 시프트 연산자

비트를 왼쪽 혹은 오른쪽으로 미는 시프트 연산자도 지원한다.


부호없는 Integer의 시프팅

let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

아래 예제에서 pink 와 16진수와 AND 연산을 하게 되는데 여기서 FF는 윈도우 역할을 해서 AND 연산에서 FF의 위치에 있는 값만 취해 시프트 연산을 하게 된다.

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16
// redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8
// greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF
// blueComponent is 0x99, or 153

부호가 있는 Integer의 시프팅

부호가 있는 정수형에서는 최상단의 비트가 부호를 표현한다. 0일때는 양수, 1일때는 음수를 의미한다.





오버플로우 연산자

Int16의 값은 범위 -32768~32767 값을 갖는다. Int16의 최대값인 Int16.max에 값을 하나 더하면 Int16이 저장할 수 있는 값의 범위를 벗어나므로 에러가 발생한다.

var potentialOverflow = Int16.max
// potentialOverflow equals 32767, which is the maximum value an Int16 can hold
potentialOverflow += 1
// this causes an error

만약 값이 넘치는 오버플로우가 발생하더라도 그 뒷값을 자르고 연산을 수행하려면 다음과 같이 각 연산자 앞에 & 를 붙여 수행하면 된다.

  • &+ : 오버플로우 덧셈
  • &- : 오버플로우 뺄셈
  • &* : 오버플로우 곱셈

값 오버플로우

값은 양수쪽 혹은 음수쪽 양쪽으로 넘칠 수 있다.

  var unsignedOverflow = UInt8.max
  // unsignedOverflow equals 255, which is the maximum value a UInt8 can hold
  unsignedOverflow = unsignedOverflow &+ 1
  // unsignedOverflow is now equal to 0

여기서 오버플로우 덧셈을 하면 그 결과는 다음과 같이 값이 초기화 된다.

만약 여기서 다시 오버플로우 뺄셈을 하면 최대값을 갖는다.

var unsignedOverflow = UInt8.min
// unsignedOverflow equals 0, which is the minimum value a UInt8 can hold
unsignedOverflow = unsignedOverflow &- 1
// unsignedOverflow is now equal to 255


부호를 갖는 Int형의 경우 오버플로우 뺄셈 연산을 하면 결과는 다음과 같다.

var signedOverflow = Int8.min
// signedOverflow equals -128, which is the minimum value an Int8 can hold
signedOverflow = signedOverflow &- 1
// signedOverflow is now equal to 127

연산자 수행의 우선순위

연산자 별로 우선순위가 있어서 어떤 등식의 순서대로 연산이 수행되는 것이 아니라 연산자의 우선순위 별로 연산을 수행한다.

2 + 3 % 4 * 5
// this equals 17

연산자 메소드

+, ++ 같은 연산자는 메소드로 수행되고 이 메소드를 오버라이ㅣㅇ 할 수 있다. 아래 예제는 2D Vector 구조체를 더하는 + 메소드를 선언한 예이다.

struct Vector2D {
    var x = 0.0, y = 0.0
}

extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

vector + anotherVector 를 수행하면 + 메소드가 수행되면서 두 2차원 좌표의 x, y 값을 각각 더한다.

접두, 접미 연산자

어떤 피 연산자 앞에 붙이는 접두 연산자를 정의할 수 있다. 아래와 같이 -를 붙이면 이후 값을 음수로 변환하도록 함수를 정의한다.

extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
}

아래코드를 수행하면 2차원 좌표가 음수로 변한 것을 확인할 수 있다.

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative is a Vector2D instance with values of (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive is a Vector2D instance with values of (3.0, 4.0)

할당 연산자의 합성

할당 연산자를 오버라이딩 할 수 있다. 아래는 += 연산자를 재정의한 예이다, 좌변은 in-out 파라미터로 좌변에 좌변과 우변을 더한 값을 할당한다.

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}

위 할당 연산자를 실행하면 아래와 같이 원래 값에 더한 값이 추가된 것을 확인할 수 있다.

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)

등위 연산자

두 값 혹은 객체를 비교하는 등위 연산자 == 를 오버라이딩 할 수 있다. 다음은 2차원 좌표의 등위를 비교하는 == 연산자를 오버라이딩한 예제이다.

extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y)
    }
}

두 좌표의 x, y가 각각 같은 경우에만 같다고 판별한다.

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}
// Prints "These two vectors are equivalent."

Swift에서는 등위 연산자의 구현을 자동으로 합성해 주기도 한다. 다음의 경우 Swift에서 등위 연산에 대해 자동으로 제공해 준다.

  • 구조체가 저장 프로퍼티만 갖는 경우 Equatable 프로토콜을 따르게 된다.

  • 열거형이 연관 타입만 갖는 경우 Equatable 프로토콜을 따르게 된다.

  • 열거형이 연관 타입이 없는 경우 Swift가 자동으로 제공하는 등위 연산을 이용해 3차원 좌표의 등위도 아래와 같이 비교할 수 있다. 3차원 좌표 구조체는 저장 프로퍼티만 있기 때문에 Swift에서 자동으로 등위연산을 제공해 준다.

struct Vector3D: Equatable {
    var x = 0.0, y = 0.0, z = 0.0
}

let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
    print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."

커스텀 연산자

기본 연산자에는 커스텀 전위 연산자 +++ 를 사용할 수 있다.

prefix operator +++

이 연산은 자신의 x, y 값을 각각 2배하는 연산을 수행하도록 정의한다.

extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}

var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)

정의한대로 +++ 연산자가 동작하는 것을 확인할 수 있다.

중위 연산자의 수행

다음과 같이 두 피연산자 사이에 존재하는 중위 연산자를 정의해 사용할 수 있다. x 값은 더하고 y 값은 빼는 연산으로 정의한 예제이다.

infix operator +-: AdditionPrecedence
extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector is a Vector2D instance with values of (4.0, -2.0)

+- 중위 연산이 정의한 대로 동작하는 것을 확인 할 수 있다.

profile
iOS 앱개발
post-custom-banner

0개의 댓글