[Swift/프로그래머스] 세균증식 (pow 함수)

sonny·2024년 12월 14일
2

TIL

목록 보기
71/133

나의 답)

import Foundation

func solution(_ n:Int, _ t:Int) -> Int {
    var result = n
    for i in 1...t {
        result *= 2
    }
    return result
}

한 시간의 두배만큼 증식하는거면 경과한 시간마다 X2를 해주면 되겠다 싶어 바로 for문이 생각나서 초기 세균의 수를 result 값에 지정하고,

반복문을 통해 세균 마릿 수가 몇 마리던 하나씩 모두 2를 곱해주었다.

값은 잘 맞았고 정답이긴 했는데, 다른 사람의 풀이를 보다가 pow 라는 것을 이용해 간단히 풀었던 공식을 보게 됐다.
.
.
.

거듭제곱은 pow

func pow(_ x: Double, _ y: Double) -> Double

매개변수

  • x : 밑(base) 숫자
  • y : 지수(exponent) 숫자

반환값

  • x를 y 제곱한 값(결과는 Double 타입)

알아보니 Swift에서는 거듭제곱 연산자를 제공하지 않아서, pow 함수를 사용해야 한다고 한다.

기본적으로 powFoundation 라이브러리에 포함되어 있고, Swift에서 제공하는 제곱 함수라서 숫자의 거듭제곱을 계산할 때 사용된다고 한다.

테스트 해보려는데 Decimal 오류는 무엇인가

위에서 Double타입으로 하는건 알았지만 그냥 Int로 해보고 싶었다.

역시나 되지 않았다.

오류를 확인해보니 Int타입의 값을 Decimal 타입의 매개변수에 전달할 수 없다는 의미라고 하는데,

swift에서는 서로 다른 데이터타입을 명시적으로 변환해야하고, IntDecimal로 자동 변환하지 않는다고 한다.

Decimal은 뭐지

swift에서 pow함수와 Decimal 타입을 함께 사용하는 이유는 Decimal 타입이 정밀한 실수 연산을 지원하기 때문이라고 한다.

Decimal은 고정 소수점 타입으로, 부동 소수점 타입(Double이나 Float)과 다르게 정확한 계산이 필요한 경우 사용된다고 한다.

주로 금융 계산처럼 높은 정밀도가 필요한 상황에서 유용하다고 .. 오..

.
.
.

아무튼 Fix를 눌러보았고 이렇게 Decimal이 붙었다.

근데 왜 num1 만 감싸고 num2는 버려둔건지 모르겠다.

바로 이럴 때 공식문서를 봐야 한다.

Decimal로 감싸는 이유는 pow 함수의 첫 번째 매개변수가 Decimal 타입이어야 하기 때문인 것인데,

Swift는 매개변수의 타입에 맞는 값을 요구하고 num1Decimal로 변환한 이유는 다음과 같은 규칙 때문이다.

1. pow 함수의 요구사항

pow 함수가 Decimal 타입에서 동작하려면, 첫 번째 매개변수가 Decimal이어야 하고,

두 번째 매개변수(num2)는 Int 타입이어도 된다.

이건 Swift가 powDecimal 확장 구현에서 두 번째 매개변수를 정수로 허용하기 때문이라고 한다.

Decimal 확장 pow 함수의 정의

func pow(_ base: Decimal, _ exponent: Int) -> Decimal
  • baseDecimal 타입이어야 함.
  • exponentInt 타입이어야 함.

따라서 num1Decimal로 변환하면, pow 함수의 정의와 일치하므로 올바르게 작동된다.

2. num2는 변환하지 않아도 되는가

pow 함수의 두 번째 매개변수(exponent)는 이미 Int 타입이다.

따라서 별도의 변환 없이도 함수 정의에 적합하다는 것인데, 그래서 num2는 추가 작업 없이 그대로 사용이 가능하다.

3. 전체 흐름

import Foundation

let num1 = 2               // Int 타입
let num2 = 3               // Int 타입
let result = pow(Decimal(num1), num2) // num1만 Decimal로 변환
print(result) // 8
  • num1 (Int) → Decimal(num1)로 변환: Decimal 타입 요구를 만족시킴.
  • num2 (Int) 그대로 사용: 함수 정의에서 허용되므로 변환 불필요.

만약 모든 매개변수를 Decimal로 통일하고 싶다면, num2도 명시적으로 변환할 수 있다.

let num1 = 2
let num2 = 3
let result = pow(Decimal(num1), Decimal(num2)) // num2도 Decimal로 변환

print(result) // 8

이 경우, 정확히 동일한 결과를 얻을 수 있지만 불필요한 변환 작업이 추가된다.

내 코드에서 Decimalnum1만 감싼 것은 함수의 정의를 만족시키는데 충분하기 때문에 굳이 두개를 다 감쌀 필요가 없었다.

불필요한 변환은 피하고 필요한 부분만 변환하는 것이 Swift에서 권장되는 방법이라고 한다.

진짜 swift가 대학을 갔다면 카이스트였을 것 같다. 어마무시하다.

Double 타입으로도 가능했다.

pow 함수는 기본적으로 Double 타입의 매개변수를 받도록 설계되어 있어서,

Int 타입인 num1num2Double 로 변환한 후 사용하는 것도 가능하다.

아까 사용됐던 Decimal과 지금Double의 경우 차이

  • Double을 사용한 경우

    • 부동 소수점 연산으로 빠른 계산.
    • 수학 함수에서 기본적으로 사용하는 타입.
    • 소수점이 포함된 값도 처리 가능.
  • Decimal을 사용한 경우

    • 정밀한 소수 연산이 필요한 경우 적합. (금융 계산)
    • 처리 속도는 Double보다 느릴 수 있음.
    • 함수 정의에 따라 필요한 경우 (powDecimal 확장 등).

그래서 어떻게 풀었냐면...

바로 이렇게 풀었다.

func solution(_ n: Int, _ t: Int) -> Int {
    return n * Int(pow(2.0, Double(t)))
}

pow(2.0, Double(t))2t제곱한 값을 반환하니 세균이 1시간마다 두 배가 되어서, t시간 후에는 2^t배로 증식하게 된다.

그리고 처음 세균 수 n2^t를 곱해 최종 세균 수를 계산하면 되는 것이다.

코드를 통해 수학도 하고 ... 여러모로 swift 덕분에 많이 배운다.

  • n : 세균의 개수 (Int 타입)
  • t : 시간 (Int 타입)

pow(2.0, Double(t))

pow 함수는 거듭제곱을 계산하는 함수인거는 이제 공부를 해서 알았고,

여기서는 2를 t번 곱한 값을 계산하는 것인데,

만약 t3이라면 pow(2.0, 3)2^3 = 8이 된다는 것이다.

Double(t)는 Int 타입이기 때문에 pow 함수의 두 번째 인자는 Double 타입이어야 한다.

그래서Double(t)tDouble 타입으로 변환했다.


왜 Double으로 변환이 필요한지 다시 짚어보자면,

Int 타입의 tDouble 타입으로 변환하는 이유는 pow 함수가 Double 타입의 값을 요구하기 때문이다.

Int는 정수고 Double은 실수라서 두 타입 간에는 직접적인 연산이 불가능하다.

그래서 tDouble(t)로 명시적으로 변환해주는 것이라고 보면 된다.


넘어가서, Int(pow(2.0, Double(t)))

pow 함수는 Double 타입의 값을 반환했지만 nInt 타입이기 때문에 pow(2.0, Double(t))의 현재 결과도 Double이다.

그럼 이걸 Int 타입으로 변환해야 한다. 정답은 정수이니까.

그래서 Int()로 감싸서 정수로 변환한 것이다.

n * Int(pow(2.0, Double(t)))

그리고 마지막으로 초기 세균의 수 n2^t를 곱한 결과가 계산된다.

이 연산은 n이 처음 주어진 세균의 수고, t는 시간에 따라 2배씩 증가하는 세균 수의 증가율을 나타내기 때문이다.

그렇게 최종적으로 계산된 세균의 수를 return으로 반환해주면 ,,

굿


음...

오늘 pow 함수에 대해 공부하면서 여러 가지 중요한 내용을 알게 되었다.

수학을 모르다보니 제곱근과 거듭제곱의 개념이 혼동되기도 했었다. ㅎㅎ....

공부하면서 pow 함수는 두 숫자의 거듭제곱을 계산하는 함수라는 것도 확인했고, 기본적으로 Double 타입의 값을 받는 함수라는 것과 Int 타입의 값을 넘기려면 Double로 변환해줘야 한다는 것을 배웠다.

아까 Int 타입의 num1과 num2를 Double(num1)과 Double(num2)로 변환하여 사용해야 한다는 점에서 타입 변환에 대한 이해가 좀 필요했어서 시간이 좀 걸린 듯 하다.

그리고 pow 함수는 반환 값이 항상 Double 타입이라서 계산된 결과가 소수점을 포함하는 실수로 나온다는 점도 알게 됐는데, 만약 2의 3제곱을 계산하면 8이 아닌 8.0이 출력된다.

그리고 위에 말했던 Decimal 타입을 사용해 더 정밀한 계산을 할 수도 있다는 것도 배우고, 그 사용법을 알아봤다. (Fix로 인해 알게 되었지만..)

다만 Decimal을 사용할 경우 성능에 약간의 영향이 있을 수 있기 때문에, 일반적인 경우에는 Double 타입을 사용하는 것이 더 효율적이라고 한다. 오호.

아무튼 주말에는 과제를 잠시 떠나 이렇게 문제를 푸는게 리프레시 되는 기분이라 좀 좋은 것 같기도.

profile
iOS 좋아. swift 좋아.

0개의 댓글

관련 채용 정보