환전

환전

학습 연습 문제

소개

Julia는 대부분의 프로그래밍 작업에 사용할 수 있는 범용 언어예요. 하지만 실제로는 공학과 과학 분야에서 주로 쓰여요. 빠르고 다재다능하며 정교한 수치 계산이 Julia 설계의 중심이에요.

정수

정수는 소수점이 없는 "딱 떨어지는" 수예요.

기초 개념에서 정수 값을 자료형을 지정하지 않고 변수에 할당할 수 있다는 걸 봤어요.

가독성을 위해 밑줄을 자릿수 구분자로 사용할 수 있어요. 컴파일러는 이 밑줄을 무시해요.

julia> x = 3
3

julia> typeof(x)
Int64

julia> large_number = 1_234_567_890
1234567890

부동소수점

부동소수점 수에 소수점이 있고, 소수점 뒤에 소수 부분이 있다는 건 놀랍지 않을 거예요.

julia> f = 3.45
3.45

julia> typeof(f)
Float64

물론 과학적 표기법도 지원해요.

julia> avogadro = 6.02e23
6.02e23

최댓값과 최솟값은 의외일지도 몰라요:

julia> typemax(Float64)
Inf

julia> typemin(Float64)
-Inf

무한대도 유효한 값이에요!

산술 연산자

기초 개념에서 이야기했듯이, 산술 연산자는 아이들에게 가르치는 일반적인 산수와 거의 똑같이 동작해요. 거듭제곱에는 **가 아니라 ^를 쓴다는 점을 기억해 둬요 (둘 다 다른 언어에서는 흔히 볼 수 있어요).

2 + 3  # 5 (addition)
2 - 3  # -1 (subtraction)
2 * 3  # 6 (multiplication)
8 / 2  # 4.0 (division)
8 % 3  # 2 (remainder)
2 ^ 3  # 8 (exponentiation)

그런데 Julia만의 몇 가지 세부 사항은 짚고 넘어갈 만해요.

곱셈

julia> x = 4.2
4.2

julia> 2 * x
8.4

julia> 2x
8.4

julia> 2.4x
10.08

이건 좀 놀라울 수도 있어요.

대부분의 다른 프로그래밍 언어처럼 *를 중위 연산자로 쓰는 건 언제나 가능해요.

하지만 Julia는 코드가 최대한 수학 공식처럼 보여야 한다고 믿는 사람들이 설계했어요.

변수 이름은 반드시 문자로 시작해야 하기 때문에, 이름 앞에 숫자(정수든 부동소수점이든)를 붙이면 암시적 곱셈으로 처리돼요.

예를 들어 구의 겉넓이를 구할 때 4 * pi * r * r 대신 이렇게 할 수 있어요:

julia> surface(r) = 4π * r^2
surface (generic function with 1 method)

julia> surface(3)
113.09733552923255

π는 내장 상수이지만 (그리스) 문자이기도 해요. 그래서 파서는 π와 r을 구분하기 위해 명시적인 * 하나가 여전히 필요해요.

나눗셈

/를 중위 연산자로 사용하면 정수를 입력해도 항상 부동소수점 결과가 나와요.

정수 나눗셈에는 더 많은 선택지가 있어요.

julia> 10 / 3  # floating-point division
3.3333333333333335

julia> div(10, 3)  # integer division
3

julia> 10 ÷ 3  # synonym for div()
3

julia> 10 // 3  # rational number (fraction)
10//3

div() 함수는 정수 나눗셈을 위한 것으로, 결과는 0 방향으로 버려져요. 양수는 내림, 음수는 올림이에요.

같은 의미로 중위 연산자 ÷를 쓸 수 있는데, 역시 더 수학처럼 보이게 하려는 거예요. Julia를 인식하는 편집기를 쓴다면 \div를 입력한 뒤 <Tab> 키를 누르면 돼요.

// 연산자는 이 개념의 범위를 벗어나요. 지금은 //의 결과가 "유리수"이고, 대부분의 사람들이 이를 _분수_라고 부른다고만 알아둬요.

숫자형 변환

이런 변환은 자주 자동으로 일어나요:

julia> x = 2 + 3.5
5.5

julia> typeof(x)
Float64

Int64와 Float64를 더했더니 Float64 결과가 나왔어요.

사실 덧셈을 하기 전에 정수가 조용히 Float64로 변환된 거예요.

부동소수점에서 정수로의 변환은 어쩔 수 없이 더 복잡해요. 소수점 뒤에 있는 값은 어떻게 처리하고 싶나요?

  • round() 함수는 가장 가까운 정수로 변환하는데, 4.5처럼 정확히 중간에 있는 값은 가장 가까운 _짝수_로 반올림해요.
  • floor()는 내림, ceil()은 올림, trunc()는 0 방향으로 버림이에요.
  • Int32()처럼 직접 캐스팅하려고 하면 InexactError와 함께 실패해요.

그런데 이 함수들은 기본적으로 원했던 정수형을 반환하지 않아요. 원하는 출력 자료형을 지정할 수 있어요.

julia> round(4.5)
4.0

julia> ceil(Int, 4.3)
5

소수점 뒤 자릿수를 지정해 반올림하는 것도 digits 키워드로 가능해요.

julia> round(π, digits=10)
3.1415926536

0으로 나누기

오류가 발생한다고 생각하나요? 사실 상황은 그렇게 단순하지 않아요.

예상했겠지만, ÷나 //를 사용한 정수 나눗셈은 오류가 발생해요.

/를 사용한 부동소수점 나눗셈은 일반적인 컴퓨터 과학 방식이 아니라, 엔지니어링 방식이라고 할 만한 접근을 취해요:

julia> 2 / 0
Inf

julia> 0 / 0
NaN

앞에서 이야기했듯이, Julia에서 무한대는 유효한 부동소수점 수이고 Inf로 나타내요.

분자도 0이면 결과는 수학적으로 정의되지 않아요. 그러면 Julia는 이를 "숫자가 아님"으로 처리하고, NaN으로 나타내요.

지침

친구 Chandler는 세계 곳곳의 이국적인 나라들을 여행할 계획이에요. 안타깝게도 Chandler는 수학 실력이 좋지 않아요. 여행 중에 환전소에서 바가지를 쓸까 봐 꽤 걱정하고 있고, 그래서 환율 계산기를 하나 만들어 달라고 부탁했어요. 다음은 앱에 대한 Chandler의 요구 사항이에요:

1. 환전 후 가치 추산하기

exchange_money() 함수를 만들어요. 매개변수는 두 개예요:

  1. budget : 환전하려는 금액이에요.
  2. exchange_rate : 외화 한 단위에 해당하는 자국 통화의 금액이에요.

이 함수는 환전한 통화의 가치를 반환해야 해요.

참고: 통화가 USD이고, 환율이 1.20인 상태에서 USD를 EUR로 환전하려 한다면 1.20 USD == 1 EUR예요.

julia> exchange_money(127.5, 1.2)
106.25

2. 환전 후 남은 금액 계산하기

get_change() 함수를 만들어요. 매개변수는 두 개예요:

  1. budget : 환전 전의 금액이에요.
  2. exchanging_value : 환전하기 위해 예산에서 빠져나가는 금액이에요.

이 함수는 예산에서 남은 금액을 반환해야 해요.

julia> get_change(127.5, 120)
7.5

3. 지폐의 가치 계산하기

get_value_of_bills() 함수를 만들어요. 매개변수는 두 개예요:

  1. denomination : 지폐 한 장의 액면가예요.
  2. number_of_bills : 전체 지폐의 개수예요.

이 환전소는 특정 단위의 현금만 취급해요. 받게 되는 총액은 "지폐" 한 장, 즉 한 단위의 값으로 나누어떨어져야 해요. 그런데 나머지나 소수 부분이 남을 수 있어요. 이 함수는 환전소가 돌려주는 지폐의 총 가치만 (소수 부분을 제외하고) 반환해야 해요. 안타깝게도 환전소는 나머지나 거스름돈을 보너스 삼아 챙겨요.

julia> get_value_of_bills(5, 128)
640

4. 지폐의 개수 계산하기

get_number_of_bills() 함수를 만들어요. 매개변수는 amount와 denomination이에요.

이 함수는 주어진 금액 안에서 받을 수 있는 _지폐의 개수_를 반환해야 해요. 다시 말해, 처음 금액 안에 _온전한 지폐_가 몇 장 들어갈까요? 지폐는 _온전한 단위_로만 받을 수 있고, 지폐의 일부를 받을 수는 없다는 점을 기억하고 그에 맞게 나눠요. 결국 가장 가까운 지폐 단위로 _내림_하는 셈이에요.

julia> get_number_of_bills(127.5, 5)
25

5. 지폐로 환전한 뒤 남은 금액 계산하기

get_leftover_of_bills() 함수를 만들어요. 매개변수는 amount와 denomination이에요.

이 함수는 지폐 단위를 고려했을 때 처음 _금액_에서 돌려줄 수 없는 _나머지 금액_을 반환해야 해요. 환전소가 얼마를 챙기는지 정확히 아는 것이 아주 중요해요.

julia> get_leftover_of_bills(127.5, 20)
7.5

6. 환전 후 가치 계산하기

exchangeable_value() 함수를 만들어요. 매개변수는 budget, exchange_rate, spread, denomination이에요.

spread 매개변수는 환전 수수료로 떼가는 비율이며, 정수로 표현해요. 100으로 나누어 소수로 변환해야 해요. 1.00 EUR == 1.20 USD이고 spread가 10이라면, 실제 총 환율은 1.00 EUR == 1.32 USD가 돼요. 1.20의 10%인 0.12가 추가 수수료로 환율에 더해지기 때문이에요.

이 함수는 환율에 spread를 더해 계산한 뒤, 새 통화의 최댓값을 반환해야 해요. 통화의 denomination은 정수이고 더 이상 나눌 수 없다는 점을 기억해요.

참고: 반환값은 정수형이어야 해요.

julia> exchangeable_value(127.25, 1.20, 10, 20)
80

julia> exchangeable_value(127.25, 1.20, 10, 5)
95
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Julia Exercism

환전 문제를 시작해 볼 준비가 됐나요?

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