고백할게 있습니다. 저는 부동 소수점 숫자를 싫어합니다. 물론, 컴퓨터라면 유용하지만, 사람이라면 다음과 같은 상황에서 왼쪽 머리를 긁적입니다.
129.95 * 100
# => 12994.999999999998
이것은 수학적 조화에 직면할 뿐만 아니라 나쁜 UX입니다.
레시피에서 밀가루 0.37211927843컵을 측정하라고 하면 작성자가 바보인지 스스로 웃으며 컵의 3분의 1을 측정하기 시작했을 것입니다.
대부분의 사람들은 임의의 십진수에 대해 생각할 수 있는 것보다 훨씬 더 쉽게 분수에 대해 생각할 수 있습니다. 따라서 앱에서 사람들에게 숫자를 전달하려는 경우 숫자를 분수로 표현하는 방법을 찾는 것이 좋습니다.
Ruby의 Rational
class는 유리수 작업을 위한 훌륭한 도구입니다. 그것은 당신에게 합리적인 수학을 할 수 있는 능력을 제공할 뿐만 아니라, 또한 당신이 근사한 부동 소수점 숫자를 근사하는 간단한 분수를 찾을 수 있게 해줍니다. 살펴보겠습니다!
합리성이란 무엇입니까?
우리의 목적을 위해 "유리수"는 "분수"를 말하는 멋진 방법입니다. 분자와 분모의 두 부분으로 구성됩니다.
1/2 # Numerator is 1. Denominator is 2.
5 # Numerator is 5. Denominator is 1.
Ruby에서 유리수는 정수 및 부동 소수점 숫자와 마찬가지로 고유한 데이터 유형을 갖습니다. 새로운 합리성을 만드는 몇 가지 방법이 있습니다.
3/2r # This syntax was introduced in Ruby 2.1
1.5.to_r # Floats can be converted to rationals via `to_r`
"3/2".to_r # ...so can strings
Rational('3/2') # This is how we had to do things in the olden days
Rational(3, 2) # ...see how hard life was?
간단한 수학
두 개의 유리수를 더하거나 빼거나 곱하거나 나누면 결과도 유리합니다.
2/3r + 1/3r
# => (1/1)
2/3r - 1/3r
# => (1/3)
2/3r * 1/3r
# => (2/9)
(2/3r) / (1/3r) # We need parens here to avoid confusing the interpreter
# => (2/1)
다른 모든 수학 연산자도 예상대로 작동합니다. **
, >
, <
등.
일반적인 규칙은 결과가 분수가 되려면 두 입력이 모두 분수여야 한다는 것입니다. 내가 찾을 수있는 한 가지 예외는 정수입니다. 모든 정수는 합리적이므로 Ruby는 똑똑한 작업을 수행하고 모든 사람이 합리적인 출력을 가정한다고 가정합니다.
2/3r + 2
# => (8/3)
근사치
유리수에 대한 가장 유용한 점 중 하나는 우리가 머리로 근사하고 쉽게 계산할 수 있다는 것입니다. 이것을 이용하려면 분수를 단순하게 유지해야 합니다. 3/2
3320774221237909/2251799813685248
대신 .
다행히 Ruby는 정확하지만 못생긴 숫자를 근사하지만 예쁜 숫자로 쉽게 변환할 수 있는 방법을 제공합니다. 저는 rationalize
에 대해 이야기하고 있습니다. 방법.
다음과 같습니다.
# Precise but ugly
(1.47472).to_r
=> (3320774221237909/2251799813685248)
# Less precise, but pretty
(1.47472).to_r.rationalize(0.05)
=> (3/2)
합리화 방법에는 하나의 인수가 있습니다. 단순성을 위해 기꺼이 교환하려는 정밀도의 정도인 허용 오차를 지정합니다.
이 방법은 허용 오차 내에서 분모가 가장 낮은 숫자를 찾습니다. 제가 의미하는 바는 다음과 같습니다.
# What's the number with the lowest denominator between 5/10 and 7/10?
(6/10r).rationalize(1/10r)
# => (1/2)
# What's the number with the lowest denominator between 11/20 and 13/20?
(6/10r).rationalize(1/20r)
=> (3/5)
# ..and between 1/10 and 11/10?
(6/10r).rationalize(1/2r)
=> (1/1)
크루더 근사치
분수에 해당하는 정수 또는 부동 소수점 수를 찾기만 하면 여러 가지 옵션이 있습니다.
# Return the nearest integer.
(6/10r).round
# => 1
# Round down
(12/10r).to_i
# => 1
합리성의 한계
유리수와 Ruby로 작업할 때 알아야 할 몇 가지 제한 사항이 있습니다. 물론 0으로 나눌 수는 없습니다.
4/0r
ZeroDivisionError: divided by 0
무리한 수를 합리적으로 취급하려고 하면 이상한 행동을 하게 될 것입니다.
# Umm, isn't the square root of 2 irrational?
Rational(Math.sqrt(2))
# => (6369051672525773/4503599627370496)
# And I'm pretty sure PI is irrational as well.
Rational(Math::PI)
# => (884279719003555/281474976710656)
우리는 Ruby에게 무리수를 처리하도록 요청하는 것이 합리적이라고 생각하면 일종의 예외가 발생할 것이라고 기대할 수 있습니다. 그러나 불행히도 Ruby는 이것을 할 만큼 똑똑하지 않은 것 같습니다. 대신, 이러한 무리수에 대한 부동 소수점 근사값을 유리수로 변환합니다. 큰 문제는 아니지만 주의해야 할 사항입니다.