Rational numbers는 정수 분자를 정수 분모로 나눈 분수예요.
예를 들어 2//3을 근삿값인 Float64 값 0.6666... 대신 정확한 분수로 저장할 수 있어요.
장점은 (integer overflow라는 극단적인 경우만 빼면) 유리수가 정확한 값을 그대로 유지해서, 부동소수점 수에서 흔히 피할 수 없는 반올림 오류를 피할 수 있다는 점이에요.
유리수는 아주 단순한 숫자 타입이고, 기대하는 대로 동작하도록 만들어졌어요. 초기 버전부터 Julia의 표준 타입이었기 때문에, 대부분의 함수가 정수나 실수에서처럼 유리수도 입력으로 받아요.
만드는 방법은 간단해요. 두 정수 사이에 //를 쓰면 돼요.
julia> 3//4
3//4
julia> a = 3; b = 4;
julia> a//b
3//4
공통 인수는 자동으로 제거되어 분수가 "가장 간단한 형태"로 바뀌어요. 즉, 그 분수를 정확히 나타내는 가장 작은 정수들이 되고, 분모는 음수가 아니에요.
julia> 5//15
1//3
julia> 5//-15
-1//3
일반적인 arithmetic operators인 + - * / ^ %는 유리수에서도 다른 숫자 타입과 거의 똑같이 동작해요.
정수와 다른 Rational들을 함께 써도 결과는 Rational이에요.
식에 float을 포함하면 결과도 float이 되고, 그에 따라 정밀도가 (어쩌면) 떨어질 수 있어요.
float이 필요하면 그냥 float() 함수로 유리수를 변환하면 돼요.
긴 계산 동안 정밀도를 유지하려고 유리수를 쓰고, 마지막에 실수로 변환하는 건 아주 흔한 일이에요.
julia> 3//4 + 1//3 # addition
13//12
julia> 3//4 * 1//3 # multiplication
1//4
julia> 3//4 / 1//3 # division
9//4
julia> 3//4 ^ 2 # exponentiation
3//16
julia> 3//4 + 5 # rational and int => rational
23//4
julia> 3//4 + 5.3 # rational and float => float
6.05
julia> float(3//4) # casting
0.75
Julia에서 유리수는 그냥 숫자예요. 컴파일러가 보통 필요에 따라 타입을 변환해 줘요.
다만 비교는 유한 소수로 나타낼 수 있는 분수에서만 기대한 대로 동작하니 주의해요.
julia> 3//4 == 0.75
true
julia> 3//4 < 0.74
false
그 밖의 경우에는 비교하려면 Rational을 Float로 변환해야 해요.
julia> 1//3 == 1/3
false
julia> float(1//3) == 1/3
true
수학 함수는 유리수를 입력으로 받지만, 부동소수점 결과를 내놓을 수도 있어요.
julia> sqrt(9//16)
0.75
어느 연구 기관은 신입 연구원 일부가 분석에서 최선이 아닌 방법을 사용해 왔다는 것을 알아챘어요. 그중 하나는 추가 계산을 하기 전에 이산 확률을 실수(즉, 부동소수점 수)로 곧바로 변환하는 방법이에요.
선임 연구원들은 더 높은 정밀도를 얻을 수 있는 유리수를 계산에 사용하는 쪽을 선호하고, 신입 연구원들의 좋지 않은 관행이 연구 결과에 영향을 주었는지 알고 싶어 해요.
수행된 연구에는 두 가지 유형이 있었어요.
선임 연구원들은 실수를 사용한 분석에 반올림 오류가 있는지 판단하는 데 도움이 될 함수를 작성해 달라고 요청해요. 그리고 오류가 있다면 결과에 대한 정확한 유리수를 제공해 달라고도 해요.
rationalize(successes, trials) 함수는 successes와 trials 두 배열을 받아요.
인덱스 i에 대해, successes[i]는 trials[i]번의 시행에서 일어난 성공 횟수에 해당해요.
이 함수는 입력 배열과 같은 순서로, 시행 횟수에 대한 성공 횟수의 유리수 배열을 반환해요.
julia> rationalize([1, 2, 3], [4, 5, 6])
3-element Vector{Rational{Int64}}:
1//4
2//5
1//2
마찬가지로, probabilities(successes, trials) 함수는 successes와 trials 두 배열을 받아요.
입력 배열과 같은 순서로, 시행 횟수에 대한 성공 횟수의 실수 배열을 반환해요.
julia> probabilities([1, 2, 3], [4, 5, 6])
3-element Vector{Float64}:
0.25
0.4
0.5
checkmean(successes, trials)는 successes와 trials 두 배열을 받아요.
실수 확률의 평균과 유리수 확률의 평균을 비교해요.
checkmean은 true를 반환해요.checkmean은 유리수 확률을 반환해요.julia> successes, trials = [9, 4, 7, 8, 6], [22, 22, 11, 17, 12];
julia> checkmean(successes, trials)
true
julia> successes, trials = [6, 5, 9, 8, 9], [21, 19, 13, 25, 22];
julia> checkmean(successes, trials)
1873629//4754750
checkprob(successes, trials)는 successes와 trials 두 배열을 받아요.
실수 확률의 전체 확률과 유리수 확률의 전체 확률을 비교해요.
checkprob은 true를 반환해요.checkprob은 유리수 확률을 반환해요.julia> successes, trials = [2, 9, 4, 4, 5], [15, 11, 17, 19, 15];
julia> checkprob(successes, trials)
true
julia> successes, trials = [9, 8, 5, 4, 3], [22, 14, 19, 25, 18];
julia> checkprob(sucesses, trials)
12//7315
Exercism에 가입하고 Julia 트랙을 개념 35개연습 문제 128개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.