Numeric
Numeric
Numeric은 모든 상위 수치 클래스가 상속해야 하는 최상위 클래스예요.
출처: Ruby 3.3 API
본문
Numeric은 힙에 할당된 객체의 인스턴스화를 허용해요. Integer 같은 다른 코어 수치 클래스는 immediate로 구현돼요. 즉 각 Integer는 항상 값으로 전달되는 단일 불변 객체라는 뜻이죠.
a = 1
1.object_id == a.object_id #=> true
예를 들어 정수 1의 인스턴스는 언제나 하나만 존재할 수 있어요. Ruby는 인스턴스화를 막아서 이것을 보장해요. 복제를 시도하면 같은 인스턴스가 돌아와요.
Integer.new(1) #=> NoMethodError: undefined method `new' for Integer:Class
1.dup #=> 1
1.object_id == 1.dup.object_id #=> true
이런 이유로, 다른 수치 클래스를 정의할 때는 Numeric을 사용해야 해요.
Numeric을 상속하는 클래스는 coerce를 구현해야 해요. coerce는 새 클래스의 인스턴스로 타입 변환된 객체와 self를 담은 두 멤버 Array를 돌려줘요 (coerce 참고).
상속하는 클래스는 산술 연산자 메서드(+, -, *, /)와 <=> 연산자도 구현해야 해요 (Comparable 참고). 이 메서드들은 다른 수치 클래스의 인스턴스와 상호 운용성을 보장하기 위해 coerce에 의존할 수 있어요.
class Tally < Numeric
def initialize(string)
@string = string
end
def to_s
@string
end
def to_i
@string.size
end
def coerce(other)
[self.class.new('|' * other.to_i), self]
end
def <=>(other)
to_i <=> other.to_i
end
def +(other)
self.class.new('|' * (to_i + other.to_i))
end
def -(other)
self.class.new('|' * (to_i - other.to_i))
end
def *(other)
self.class.new('|' * (to_i * other.to_i))
end
def /(other)
self.class.new('|' * (to_i / other.to_i))
end
end
tally = Tally.new('||')
puts tally * 2 #=> "||||"
puts tally > 1 #=> true
여기에 있는 것들 (What's Here)
먼저 다른 곳에 있는 것들. 클래스 Numeric은:
- 클래스
Object에서 상속받아요. - 모듈
Comparable을 include해요.
여기 Numeric 클래스가 제공하는 메서드들은 다음과 같이 분류돼요:
- Querying (조회):
finite?,infinite?,integer?,negative?,nonzero?,positive?,real?,zero? - Comparing (비교):
<=>,eql? - Converting (변환):
%(modulo),-@,abs(magnitude),abs2,angle(arg,phase),ceil,coerce,conj(conjugate),denominator,div,divmod,fdiv,floor,i,imaginary(imag),numerator,polar,quo,real,rect(rectangular),remainder,round,to_c,to_int,truncate - Other (기타):
clone,dup(+@),step
Querying
finite?:self가 무한이거나 숫자가 아니면?true를 돌려줘요.infinite?:self가-Infinity, 유한,+Infinity중 어느쪽인지에 따라-1,nil,+1을 돌려줘요.integer?:self가 정수인지 여부를 돌려줘요.negative?:self가 음수인지 여부를 돌려줘요.nonzero?:self가 0이 아닌지 여부를 돌려줘요.positive?:self가 양수인지 여부를 돌려줘요.real?:self가 실수 값인지 여부를 돌려줘요.zero?:self가 0인지 여부를 돌려줘요.
Comparing
<=>:self가 주어진 값보다 작으면-1, 같으면0, 크면1, 비교할 수 없으면nil을 돌려줘요.eql?:self와 주어진 값이 같은 값이면서 같은 타입인지 여부를 돌려줘요.
Converting
%(modulo):self를 주어진 값으로 나눈 나머지를 돌려줘요.-@:self의 값을 부호 반전해서 돌려줘요.abs(magnitude):self의 절댓값을 돌려줘요.abs2:self의 제곱을 돌려줘요.angle(arg,phase):self가 양수면 0, 그 외에는Math::PI를 돌려줘요.ceil:self보다 크거나 같은 가장 작은 수를 주어진 정밀도로 돌려줘요.coerce: 주어진 other 값에 대해 배열[coerced_self, coerced_other]을 돌려줘요.conj(conjugate):self의 켤레복소수를 돌려줘요.denominator:self의Rational표현의 분모(항상 양수)를 돌려줘요.div:self를 주어진 값으로 나눈 값을 정수로 변환해 돌려줘요.divmod:self를 주어진 제수로 나눈 배열[quotient, modulus]을 돌려줘요.fdiv:self를 주어진 제수로 나눈Float결과를 돌려줘요.floor:self보다 작거나 같은 가장 큰 수를 주어진 정밀도로 돌려줘요.i:Complex객체Complex(0, self)을 돌려줘요.imaginary(imag):self의 허수부를 돌려줘요.numerator:self의Rational표현의 분자를 돌려줘요.self와 같은 부호를 가져요.polar: 배열[self.abs, self.arg]을 돌려줘요.quo:self를 주어진 값으로 나눈 값을 돌려줘요.real:self의 실수부를 돌려줘요.rect(rectangular): 배열[self, 0]을 돌려줘요.remainder: 주어진arg에 대해self-arg*(self/arg).truncate을 돌려줘요.round:self를 주어진 정밀도로 가장 가까운 값으로 반올림한 값을 돌려줘요.to_c:self의Complex표현을 돌려줘요.to_int: 필요하면 버림해서self의Integer표현을 돌려줘요.truncate:self를 주어진 정밀도로 (0 방향으로) 버린 값을 돌려줘요.
Other
clone:self를 돌려줘요. 동결(freeze)은 허용하지 않아요.dup(+@):self를 돌려줘요.step: 주어진 수들의 시퀀스로 주어진 블록을 호출해요.
Public Instance Methods
self % other → real_numeric
self를 other로 나눈 나머지를 실수로 돌려줘요. Core 및 Standard Library 클래스 중 Rational만 이 구현을 사용해요.
Rational r과 실수 n에 대해 다음 표현들은 같은 값이에요.
r % n
r-n*(r/n).floor
r.divmod(n)[1]
Numeric#divmod를 보세요.
r = Rational(1, 2) # => (1/2)
r2 = Rational(2, 3) # => (2/3)
r % r2 # => (1/2)
r % 2 # => (1/2)
r % 2.0 # => 0.5
modulo로도 별칭돼 있어요.
+self → self
self를 돌려줘요.
-self → numeric
단항 마이너스(Unary Minus) — 수신자를 부호 반전해서 돌려줘요.
self <=> other → zero or nil
self가 other와 같으면 0을, 그렇지 않으면 nil을 돌려줘요. Ruby Core나 Standard Library의 어떤 서브클래스도 이 구현을 사용하지 않아요.
abs → numeric
self의 절댓값을 돌려줘요. (magnitude로도 별칭돼 있어요.)
12.abs #=> 12
(-34.56).abs #=> 34.56
-34.56.abs #=> 34.56
abs2 → real
self의 제곱을 돌려줘요.
arg → 0 or Math::PI
self가 양수면 0을, 그 외에는 Math::PI를 돌려줘요. (angle, phase로도 별칭돼 있어요.)
ceil(digits = 0) → integer or float
self보다 크거나 같은, digits 소수 자릿수의 정밀도를 가진 가장 작은 수를 돌려줘요. Numeric은 이것을 self를 Float로 변환해 Float#ceil을 호출하는 방식으로 구현해요.
clone(freeze: true) → self
self를 돌려줘요. freeze 값이 true나 nil이 아닌 경우 예외를 발생시켜요. 관련: Numeric#dup.
coerce(other) → array
두 피연산자 self와 other로부터 만들어진, 공통 호환 타입의 두 수치 요소를 담은 2-요소 배열을 돌려줘요. Core 및 Standard Library 클래스 중 Integer, Rational, Complex가 이 구현을 사용해요.
i = 2 # => 2
i.coerce(3) # => [3, 2]
i.coerce(3.0) # => [3.0, 2.0]
i.coerce(Rational(1, 2)) # => [0.5, 2.0]
i.coerce(Complex(3, 4)) # Raises RangeError.
r = Rational(5, 2) # => (5/2)
r.coerce(2) # => [(2/1), (5/2)]
r.coerce(2.0) # => [2.0, 2.5]
r.coerce(Rational(2, 3)) # => [(2/3), (5/2)]
r.coerce(Complex(3, 4)) # => [(3+4i), ((5/2)+0i)]
c = Complex(2, 3) # => (2+3i)
c.coerce(2) # => [(2+0i), (2+3i)]
c.coerce(2.0) # => [(2.0+0i), (2+3i)]
c.coerce(Complex(3, 4)) # => [(3+4i), (2+3i)]
어떤 타입 변환이 실패하면 예외를 발생시켜요.
conjugate → self
self를 돌려줘요. (conj로도 별칭돼 있어요.)
denominator → integer
분모(항상 양수)를 돌려줘요.
div(other) → integer
self의 파생 클래스의 메서드 /를 사용해서 몫 self/other를 정수(floor 사용)로 돌려줘요. (Numeric 자체는 메서드 /를 정의하지 않아요.) Core 및 Standard Library 클래스 중 Float와 Rational만 이 구현을 사용해요.
divmod(other) → array
2-요소 배열 [q, r]을 돌려줘요. 여기서
q = (self/other).floor # Quotient
r = self % other # Remainder
Core 및 Standard Library 클래스 중 Rational만 이 구현을 사용해요.
Rational(11, 1).divmod(4) # => [2, (3/1)]
Rational(11, 1).divmod(-4) # => [-3, (-1/1)]
Rational(-11, 1).divmod(4) # => [-3, (1/1)]
Rational(-11, 1).divmod(-4) # => [2, (-3/1)]
Rational(13, 1).divmod(4.0) # => [3, 1.0]
Rational(13, 1).divmod(Rational(4, 11)) # => [35, (3/11)]
dup → self
self를 돌려줘요. 관련: Numeric#clone.
eql?(other) → true or false
self와 other가 같은 타입이고 같은 값을 가지면 true를 돌려줘요. Core 및 Standard Library 클래스 중 Integer, Rational, Complex만 이 구현을 사용해요.
1.eql?(1) # => true
1.eql?(1.0) # => false
1.eql?(Rational(1, 1)) # => false
1.eql?(Complex(1, 0)) # => false
메서드 eql?는 ==와 다른데, eql?는 타입 일치를 요구하는 반면 ==는 그렇지 않아요.
fdiv(other) → float
self의 파생 클래스의 메서드 /를 사용해서 몫 self/other를 부동소수점으로 돌려줘요. (Numeric 자체는 메서드 /를 정의하지 않아요.) Core 및 Standard Library 클래스 중 BigDecimal만 이 구현을 사용해요.
finite? → true or false
self가 유한한 수이면 true, 그렇지 않으면 false를 돌려줘요.
floor(digits = 0) → integer or float
self보다 작거나 같은, digits 소수 자릿수의 정밀도를 가진 가장 큰 수를 돌려줘요. Numeric은 self를 Float로 변환해 Float#floor를 호출하는 방식으로 구현해요.
i → complex
Complex(0, self)을 돌려줘요.
2.i # => (0+2i)
-2.i # => (0-2i)
2.0.i # => (0+2.0i)
Rational(1, 2).i # => (0+(1/2)*i)
Complex(3, 4).i # Raises NoMethodError.
imaginary → 0
self의 허수부를 돌려줘요. (imag로도 별칭돼 있어요.)
infinite? → -1, 1, or nil
self가 유한, -Infinity, +Infinity 중 어느쪽인지에 따라 nil, -1, 1을 돌려줘요.
integer? → true or false
self가 Integer이면 true를 돌려줘요.
1.0.integer? # => false
1.integer? # => true
magnitude
abs의 별칭이에요.
modulo
%의 별칭이에요.
negative? → true or false
self가 0보다 작으면 true, 그렇지 않으면 false를 돌려줘요.
nonzero? → self or nil
self가 0이 아니면 self를, 그렇지 않으면 nil을 돌려줘요. 평가에는 메서드 zero?를 사용해요. 돌려받은 self 덕분에 메서드를 체이닝할 수 있어요.
a = %w[z Bb bB bb BB a aA Aa AA A]
a.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
# => ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"]
Core 및 Standard Library 클래스 중 Integer, Float, Rational, Complex가 이 구현을 사용해요.
numerator → integer
분자를 돌려줘요.
phase
arg의 별칭이에요.
polar → array
배열 [self.abs, self.arg]을 돌려줘요.
positive? → true or false
self가 0보다 크면 true, 그렇지 않으면 false를 돌려줘요.
quo(int_or_rat) → rat, quo(flo) → flo
가장 정확한 나눗셈을 돌려줘요 (정수는 유리수, 부동소수점은 부동소수점).
real → self
self를 돌려줘요.
real? → true or false
self가 실수(Complex가 아님)이면 true를 돌려줘요.
rect → array
배열 [self, 0]을 돌려줘요. (rectangular의 별칭)
rectangular
rect로도 별칭돼 있어요.
remainder(other) → real_number
self를 other로 나눈 나머지를 돌려줘요. Core 및 Standard Library 클래스 중 Float와 Rational만 이 구현을 사용해요.
11.0.remainder(4) # => 3.0
11.0.remainder(-4) # => 3.0
-11.0.remainder(4) # => -3.0
-11.0.remainder(-4) # => -3.0
12.0.remainder(4) # => 0.0
13.0.remainder(4.0) # => 1.0
Rational(13, 1).remainder(4) # => (1/1)
Rational(13, 1).remainder(-4) # => (1/1)
Rational(-13, 1).remainder(4) # => (-1/1)
round(digits = 0) → integer or float
self를 digits 소수 자릿수의 정밀도로 가장 가까운 값에 반올림해 돌려줘요. Numeric은 self를 Float로 변환해 Float#round를 호출하는 방식으로 구현해요.
step(to = nil, by = 1) {|n| ... } → self, step(to = nil, by = 1) → enumerator, step(to = nil, by: 1) {|n| ... } → self, step(to = nil, by: 1) → enumerator, step(by: , to: nil) {|n| ... } → self, step(by: , to: nil) → enumerator
수의 시퀀스를 생성하고, 블록이 주어지면 시퀀스를 순회해요. Core 및 Standard Library 클래스 중 Integer, Float, Rational이 이 구현을 사용해요.
간단한 예시:
squares = []
1.step(by: 2, to: 10) {|i| squares.push(i*i) }
squares # => [1, 9, 25, 49, 81]
생성되는 시퀀스는 다음과 같아요.
self에서 시작해요.by간격으로 계속돼요 (0일 수 없어요).to안에 있거나to와 같은 마지막 수에서 끝나요. 즉by가 양수면to보다 작거나 같고,by가 음수면to보다 크거나 같아요.to가nil이면 시퀀스는 무한 길이예요.
블록이 주어지면 시퀀스의 각 수로 블록을 호출하고 self를 돌려줘요. 블록이 없으면 Enumerator::ArithmeticSequence를 돌려줘요.
키워드 인자: by와 to 키워드 인자가 주어지면 그 값(또는 기본값)이 스텝과 한계를 정해요.
# Both keywords given.
4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4
squares # => [16, 36, 64, 100]
3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3
cubes # => [27.0, 3.375, 0.0, -3.375, -27.0]
# Only keyword to given.
4.step(to: 10) {|i| squares.push(i*i) } # => 4
squares # => [16, 25, 36, 49, 64, 81, 100]
# No block given.
e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3))
e.class # => Enumerator::ArithmeticSequence
위치 인자: 선택 위치 인자 to와 by가 주어지면 그 값(또는 기본값)이 스텝과 한계를 정해요.
4.step(10, 2) {|i| squares.push(i*i) } # => 4
squares # => [16, 36, 64, 100]
4.step(10) {|i| squares.push(i*i) }
squares # => [16, 25, 36, 49, 64, 81, 100]
구현 참고: 모든 인자가 정수라면 루프는 정수 카운터로 동작해요. 어느 인자라도 부동소수점이면 모두 부동소수점으로 변환되고, 루프는 floor(n + n*Float::EPSILON) + 1번 실행돼요. 여기서 n = (limit - self)/step이에요.
to_c → complex
self를 Complex 객체로 돌려줘요.
to_int → integer
self를 정수로 돌려줘요. 파생 클래스의 메서드 to_i를 사용해 변환해요. Core 및 Standard Library 클래스 중 Rational과 Complex만 이 구현을 사용해요.
Rational(1, 2).to_int # => 0
Rational(2, 1).to_int # => 2
Complex(2, 0).to_int # => 2
Complex(2, 1) # Raises RangeError (non-zero imaginary part)
truncate(digits = 0) → integer or float
self를 digits 소수 자릿수의 정밀도로 (0 방향으로) 버린 값을 돌려줘요. Numeric은 self를 Float로 변환해 Float#truncate를 호출하는 방식으로 구현해요.
zero? → true or false
self가 0 값이면 true, 그렇지 않으면 false를 돌려줘요. Core 및 Standard Library 클래스 중 Rational과 Complex만 이 구현을 사용해요.
더 알아보기
Numeric을 상속하는Integer,Float,Rational,Complex문서를 보세요.- 비교 연산 모듈인
Comparable문서도 함께 확인하세요.