트랙
/
Crystal
Crystal
/
연습 문제
/
이자는 흥미로워요
이자는 흥미로워요

이자는 흥미로워요

학습 연습 문제

소개

루프는 주어진 조건에 따라 코드를 반복해서 실행할 수 있게 해 주는 제어 구조예요.

while문

while문은 주어진 조건에 따라 코드를 반복해서 실행할 수 있게 해 주는 제어 구조예요. while문 안의 코드는 조건이 참으로 평가되는 동안 계속 실행돼요. while문은 반복 횟수를 미리 알 수 없을 때 자주 사용하지만, 루프가 필요한 어떤 상황에서도 사용할 수 있어요.

조건은 루프 안의 코드가 실행되기 전에 평가돼요. 따라서 조건이 거짓이면 루프 안의 코드는 한 번도 실행되지 않아요.

i = 0
while i < 3
  puts i
  i += 1
end

# Output:
# 0
# 1
# 2

문자열을 순회하고 싶을 때는 문자열의 길이만큼 루프를 돌릴 수 있어요.

str = "Hello"
i = 0
while i < str.size
  puts str[i]
  i += 1
end

# Output:
# H
# e
# l
# l
# o

until문

until문은 while문과 같은 방식으로 동작하지만, 루프 안의 코드가 조건이 참으로 평가될 때까지 계속 실행된다는 점이 달라요. if와 unless의 차이와 같아요.

i = 0
until i == 3
  puts i
  i += 1
end

무한 루프

while문에서 흔히 하는 실수는 절대 끝나지 않는 "무한 루프"에 빠지는 거예요. 무한 루프는 조건이 참이나 거짓으로 결코 평가되지 않을 때 생길 수 있어요. 이런 경우는 대개 프로그래머의 실수 때문이에요. 예를 들어 루프 변수를 증가시키는 것을 잊는 경우죠. 하지만 때로는 무한 루프가 프로그램의 로직을 구현하는 가장 명확한 방법이기도 해요. 또는 영원히 반복하는 것이 꼭 필요한 경우도 있어요. 예를 들어 HTTP 서버는 들어오는 연결을 기다리고, 처리한 다음, 다시 다음 연결을 기다려요.

Break

break 키워드를 사용하면 루프를 일찍 빠져나갈 수 있어요. 특정 조건에서 루프를 일찍 빠져나가고 싶을 때 편리해요.

i = 0
while i <= 3
  puts i
  i += 1
  if i == 2
    break
  end
end

# Output:
# 0
# 1

Next

next 키워드를 사용하면 루프의 다음 반복으로 건너뛸 수 있어요. 루프의 특정 반복을 건너뛰고 싶을 때 편리해요.

i = 0
while i <= 3
  i += 1
  if i == 2
    next
  end
  puts i
end

# Output:
# 1
# 3

루프에서의 타입

루프 중에는 변수의 타입이 달라질 수 있어요. 다음 예제에서 a의 타입은 Int32 | String인데, 루프의 첫 번째 부분에서 Int32일 수도 있고 String일 수도 있기 때문이에요. 변수 a는 루프의 첫 번째 부분에서만 Int32 | String 타입을 가져요. 루프가 시작될 때는 Int32를 갖고, 두 번째 반복에서는 String을 갖기 때문이에요. 이 여러 타입 시스템은 나중에 자세히 설명해요. 그런데 루프의 두 번째 부분에서는 String만 갖는다는 것이 확실하기 때문에, 루프의 두 번째 부분에서 a의 타입은 String이에요. 실행 시점에는 Int32와 String을 동시에 갖는 일은 없어요.

i = 0
a = 4
while i < 3
  p typeof(a)
  # => Int32 | String
  a = "4"
  p typeof(a)
  # => String
  i += 1
end

Crystal에서는 메서드의 마지막 표현식이 그 값을 반환해요. 그런데 때로는 마지막 표현식 전에 값을 반환해야 할 때가 있어요. 이럴 때 return 키워드를 사용할 수 있는데, 이 키워드는 뒤따르는 표현식의 값을 반환해요. return 키워드 뒤에 작성된 코드는 실행되지 않아요.

def speed_limit(road_number)
    if road_number == 1
        return 50
        puts "This will not be executed"
    elsif road_number == 2
        return 80
        puts "This will not be executed"
    end
    100
end

p speed_limit(1) # => 50
p speed_limit(2) # => 80
p speed_limit(3) # => 100
Note

메서드의 마지막 표현식이 반환해야 할 값일 때는 return 키워드를 생략해야 해요.

지침

이 연습 문제에서는 예금 계좌를 다뤄요. 매년 예금 계좌의 잔액은 이자율에 따라 갱신돼요. 은행이 제공하는 이자율은 계좌에 있는 금액, 즉 잔액에 따라 달라져요:

  • 잔액이 음수일 때 3.213% (잔액이 더 음수가 돼요).
  • 잔액이 1000 달러 미만의 양수일 때 0.5%.
  • 잔액이 1000 달러 이상 5000 달러 미만의 양수일 때 1.621%.
  • 잔액이 5000 달러 이상의 양수일 때 2.475%.

네 가지 작업이 있고, 각 작업은 잔액과 이자율을 다뤄요.

1. 이자율 계산하기

잔액을 인자로 받는 SavingsAccount.interest_rate() 메서드를 구현해요. 이 메서드는 주어진 잔액에 대한 이자율을 반환해야 해요.

SavingsAccount.interest_rate(200.75)
# => 0.5

2. 이자 계산하기

잔액을 인자로 받는 SavingsAccount.interest() 메서드를 구현해요. 이 메서드는 주어진 잔액에 대한 이자를 반환해야 해요.

SavingsAccount.interest(200.75)
# => 1.00375

3. 연간 잔액 갱신 계산하기

잔액을 인자로 받는 SavingsAccount.annual_balance_update() 메서드를 구현해요. 이 메서드는 1년 후의 잔액을 반환해야 해요.

SavingsAccount.annual_balance_update(200.75)
# => 201.75375

4. 목표 잔액에 도달하기까지 걸리는 연수 계산하기

잔액과 목표 잔액을 인자로 받는 SavingsAccount.years_before_desired_balance() 메서드를 구현해요. 이 메서드는 목표 잔액에 도달하는 데 걸리는 연수를 반환해야 해요.

balance = 200.75
target_balance = 214.88
SavingsAccount.years_before_desired_balance(balance, target_balance)
# => 14
Note

원금 잔액에 단리를 적용할 때는 잔액에 이자율을 곱하고, 그 곱이 이자 금액이 돼요.

반면 복리는 이자를 주기적으로 적용하는 방식으로 계산해요. 적용할 때마다 이자 금액을 계산해 원금 잔액에 더하고, 이후 이자 계산은 더 커진 원금 잔액을 대상으로 이루어져요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Crystal Exercism

이자는 흥미로워요 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Crystal 트랙을 개념 26개연습 문제 142개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.