BigDecimal 클래스

BigDecimal 클래스

BigDecimal은 임의 정밀도(arbitrary-precision) 부동소수점 십진 연산을 제공해요. Ruby는 정수의 임의 정밀도 연산을 내장으로 지원하는데(42**13 같은 계산이 정확히 떨어져요), BigDecimal은 이를 크거나 정확한 부동소수점 수로 확장한 거예요.

출처: Ruby 3.3 API

본문

소개 (Introduction)

Ruby는 임의 정밀도 정수 연산을 내장 지원해요.

42**13  #=>   1265437718438866624512

BigDecimal은 아주 크거나 아주 정확해야 하는 부동소수점 수에 비슷한 지원을 해줘요. 십진 연산은 일반 계산에도 유용한데, 사람들이 기대하는 올바른 답을 주기 때문이에요 — 일반 이진 부동소수점 연산은 10진과 2진 사이의 변환 때문에 종종 미묘한 오차를 만들거든요.

예를 들어 이렇게 실행해보세요.

sum = 0
10_000.times do
  sum = sum + 0.0001
end
print sum #=> 0.9999999999999062

이 결과를 BigDecimal로 계산한 결과와 비교해봐요.

require 'bigdecimal'

sum = BigDecimal("0")
10_000.times do
  sum = sum + BigDecimal("0.0001")
end
print sum #=> 0.1E1

마찬가지로:

(BigDecimal("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true

(1.2 - 1.0) == 0.2 #=> false

정밀도에 관한 참고 (A Note About Precision)

BigDecimal과 다른 값을 계산할 때 결과의 정밀도는 값의 타입에 따라 달라져요.

  • 값이 Float면 정밀도는 Float::DIG + 1이에요.
  • 값이 Rational이면 정밀도는 Float::DIG + 1보다 커요.
  • 값이 BigDecimal이면 정밀도는 내부 표현에서의 값의 정밀도로, 플랫폼 의존적이에요.
  • 값이 그 외 객체면 정밀도는 BigDecimal(value) 변환 결과로 결정돼요.

정확한 십진 연산의 특수 값들

이진 부동소수점보다 정확한 만큼, BigDecimal은 몇 가지 특수 값이 필요해요.

무한대 (Infinity)

0으로 나누면 무한대를 돌려줘야 할 때가 있어요.

BigDecimal("1.0") / BigDecimal("0.0")  #=> Infinity
BigDecimal("-1.0") / BigDecimal("0.0")  #=> -Infinity

문자열 'Infinity', '+Infinity', '-Infinity'(대소문자 구분)로 무한대 수를 만들 수 있어요.

숫자 아님 (NaN)

계산 결과가 정의되지 않은 값이면 NaN(not a number)을 돌려줘요.

BigDecimal("0.0") / BigDecimal("0.0") #=> NaN

NaN은 어떤 값과도 같지 않아요. 심지어 자기 자신과도요.

n = BigDecimal('NaN')
n == 0.0 #=> false
n == n #=> false

양의 0과 음의 0

계산 결과가 현재 정밀도 한계 안에서 BigDecimal로 표현하기엔 너무 작으면 0을 돌려줘야 해요. 그 값이 음수면 음의 0을, 양수면 양의 0을 돌려줘요.

BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0
BigDecimal("1.0") / BigDecimal("Infinity")  #=> 0.0

(BigDecimal.mode로 정밀도 한계를 지정하는 방법을 참고하세요.) 비교 목적에서는 -0.00.0을 같은 것으로 봐요. 수학적으로 참된 0에는 부호가 없다는 점도 참고해요.

bigdecimal/util

require 'bigdecimal/util'을 하면 BigDecimal은 물론 네이티브 Integer, Float, Rational, String 클래스에도 to_d 메서드가 생겨요.

require 'bigdecimal/util'

42.to_d         # => 0.42e2
0.5.to_d        # => 0.5e0
(2/3r).to_d(3)  # => 0.667e0
"0.5".to_d      # => 0.5e0

JSON 처리 메서드

  • ::json_create: 주어진 객체로부터 새 BigDecimal 객체를 만들어요.
  • #as_json: self를 나타내는 2요소 해시를 돌려줘요.
  • #to_json: self를 나타내는 JSON 문자열을 돌려줘요.

이 메서드들은 JSON gem이 제공해요. 사용하려면 require 'json/add/bigdecimal' 하세요.

라이선스

Copyright © 2002 by Shigeo Kobayashi. BigDecimal은 Ruby 및 2-clause BSD 라이선스로 배포돼요. mrkn과 ruby-core 멤버들이 유지보수해요.

상수 (Constants)

상수 설명
BASE 내부 계산에 쓰는 밑값. 32비트 시스템에서 BASE는 10000으로, 4자리씩 묶어 계산함을 나타내요(더 크면 BASE**2가 32비트에 안 들어가 두 그룹을 오버플로 없이 곱하지 못해요).
EXCEPTION_ALL 오버플로·언더플로·0 나눗셈이 예외를 던질지 결정해요. BigDecimal.mode 참고.
EXCEPTION_INFINITY 계산 결과가 무한대일 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
EXCEPTION_NaN 계산 결과가 NaN일 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
EXCEPTION_OVERFLOW 계산 결과가 오버플로일 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
EXCEPTION_UNDERFLOW 계산 결과가 언더플로일 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
EXCEPTION_ZERODIVIDE 0으로 나눌 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
INFINITY, NAN 특수 값 상수예요.
ROUND_CEILING +∞ 방향으로 반올림해요. BigDecimal.mode 참고.
ROUND_DOWN 0 방향으로 내림해요. BigDecimal.mode 참고.
ROUND_FLOOR -∞ 방향으로 반올림해요. BigDecimal.mode 참고.
ROUND_HALF_DOWN 6 이상은 올리고 나머지는 내려요. BigDecimal.mode 참고.
ROUND_HALF_EVEN 짝수 이웃 쪽으로 반올림해요. BigDecimal.mode 참고.
ROUND_HALF_UP 5 이상은 올리고 나머지는 내려요. BigDecimal.mode 참고.
ROUND_MODE 결과를 적절한 유효 자릿수에 맞추려 반올림해야 할 때 어떻게 할지 결정해요. BigDecimal.mode 참고.
ROUND_UP 0에서 멀어지는 방향으로 올림해요. BigDecimal.mode 참고.
SIGN_NEGATIVE_FINITE 값이 음수이고 유한함을 나타내요. BigDecimal.sign 참고.
SIGN_NEGATIVE_INFINITE 값이 음수이고 무한함을 나타내요. BigDecimal.sign 참고.
SIGN_NEGATIVE_ZERO 값이 -0임을 나타내요. BigDecimal.sign 참고.
SIGN_NaN 값이 숫자가 아님을 나타내요. BigDecimal.sign 참고.
SIGN_POSITIVE_FINITE 값이 양수이고 유한함을 나타내요. BigDecimal.sign 참고.
SIGN_POSITIVE_INFINITE 값이 양수이고 무한함을 나타내요. BigDecimal.sign 참고.
SIGN_POSITIVE_ZERO 값이 +0임을 나타내요. BigDecimal.sign 참고.
VERSION bigdecimal 라이브러리의 버전이에요.

클래스 메서드 (Public Class Methods)

_load(p1)

마샬링(marshalling) 지원을 위한 내부 메서드예요. Marshal 모듈 참고.

double_fig → integer

Float 객체가 가질 수 있는 자릿수를 돌려줘요. 결과는 시스템 의존적이에요.

BigDecimal.double_fig # => 16

json_create(object)

as_json을 참고하세요.

# File ext/json/lib/json/add/bigdecimal.rb, line 13
def self.json_create(object)
  BigDecimal._load object['b']
end

limit(digits)

새로 생성되는 BigDecimal 숫자의 유효 자릿수를 지정한 값으로 제한해요. BigDecimal.mode가 지정한 대로 필요에 따라 반올림해요. 기본인 0은 상한이 없음을 뜻해요. 이 메서드의 한계는 ceil, floor, truncate, round 같은 인스턴스 메서드에 지정된 한계보다 우선순위가 낮아요.

mode(mode, setting = nil) → integer

예외 처리와 반올림에 대한 모드 설정을 나타내는 정수를 돌려줘요.

예외 처리를 제어하는 모드: EXCEPTION_NaN, EXCEPTION_INFINITY, EXCEPTION_UNDERFLOW, EXCEPTION_OVERFLOW, EXCEPTION_ZERODIVIDE, EXCEPTION_ALL.

예외 설정 값:

  • true - 해당 모드를 true로 설정
  • false - 해당 모드를 false로 설정
  • nil - 모드 설정을 바꾸지 않음

BigDecimal.save_exception_mode를 쓰면 예외 모드를 잠시 바꿨다가 자동으로 복원할 수 있어요. 예시는 명확성을 위해 먼저 모든 예외 모드를 false로 두고 시작해요.

반올림 방식을 제어하는 ROUND_MODE. BigDecimal.save_rounding_mode로 잠시 바꿨다 복원할 수 있어요.

NaN 모드EXCEPTION_NaN은 BigDecimal NaN이 만들어질 때의 동작을 제어해요.

  • false(기본): BigDecimal('NaN')을 돌려줘요.
  • true: FloatDomainError를 던져요.
BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
BigDecimal('NaN')                                 # => NaN
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true)  # => 2
BigDecimal('NaN') # Raises FloatDomainError

무한대 모드EXCEPTION_INFINITY는 Infinity/-Infinity가 만들어질 때 동작을 제어해요. false(기본)는 값을 돌려주고, trueFloatDomainError를 던져요.

BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false)     # => 0
BigDecimal('Infinity')                                # => Infinity
BigDecimal('-Infinity')                               # => -Infinity
BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true) # => 1
BigDecimal('Infinity')  # Raises FloatDomainError

언더플로 모드EXCEPTION_UNDERFLOW는 언더플로가 발생할 때 동작을 제어해요. false(기본)는 BigDecimal('0') 또는 BigDecimal('-Infinity')를 돌려주고, trueFloatDomainError를 던져요.

BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false)      # => 0
def flow_under
  x = BigDecimal('0.1')
  100.times { x *= x }
end
flow_under                                             # => 100
BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) # => 4
flow_under # Raises FloatDomainError

오버플로 모드EXCEPTION_OVERFLOW는 오버플로가 발생할 때 동작을 제어해요. false(기본)는 BigDecimal('Infinity') 또는 BigDecimal('-Infinity')를, trueFloatDomainError를 던져요.

BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false)     # => 0
def flow_over
  x = BigDecimal('10')
  100.times { x *= x }
end
flow_over                                             # => 100
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) # => 1
flow_over # Raises FloatDomainError

0 나눗셈 모드EXCEPTION_ZERODIVIDE는 0으로 나눌 때 동작을 제어해요. false(기본)는 Infinity/-Infinity를, trueFloatDomainError를 던져요.

BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false)       # => 0
one = BigDecimal('1')
zero = BigDecimal('0')
one / zero                                              # => Infinity
BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true) # => 16
one / zero # Raises FloatDomainError

모든 예외EXCEPTION_ALL은 위 전부를 제어해요.

BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true)  # => 23

반올림ROUND_MODE는 반올림 방식을 제어해요. 설정값은:

  • ROUND_UP: 0에서 멀어지는 방향으로 반올림. 별칭 :up.
  • ROUND_DOWN: 0 방향으로 반올림. 별칭 :down, :truncate.
  • ROUND_HALF_UP: 가장 가까운 이웃으로, 등거리면 0에서 멀어지는 방향으로. 별칭 :half_up, :default.
  • ROUND_HALF_DOWN: 가장 가까운 이웃으로, 등거리면 0 방향으로. 별칭 :half_down.
  • ROUND_HALF_EVEN(Banker's rounding): 가장 가까운 이웃으로, 등거리면 짝수 이웃으로. 별칭 :half_even, :banker.
  • ROUND_CEILING: +∞ 방향으로. 별칭 :ceiling, :ceil.
  • ROUND_FLOOR: -∞ 방향으로. 별칭 :floor.

save_exception_mode { ... }

주어진 블록을 실행하되 예외 모드를 보존해요.

BigDecimal.save_exception_mode do
  BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
  BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)

  BigDecimal(BigDecimal('Infinity'))
  BigDecimal(BigDecimal('-Infinity'))
  BigDecimal(BigDecimal('NaN'))
end

BigDecimal::EXCEPTION_*와 함께 쓰세요. BigDecimal.mode 참고.

save_limit { ... }

주어진 블록을 실행하되 정밀도 한계를 보존해요.

BigDecimal.limit(100)
puts BigDecimal.limit
BigDecimal.save_limit do
    BigDecimal.limit(200)
    puts BigDecimal.limit
end
puts BigDecimal.limit

save_rounding_mode { ... }

주어진 블록을 실행하되 반올림 모드를 보존해요.

BigDecimal.save_rounding_mode do
  BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
  puts BigDecimal.mode(BigDecimal::ROUND_MODE)
end

BigDecimal::ROUND_*와 함께 쓰세요. BigDecimal.mode 참고.

인스턴스 메서드 (Public Instance Methods)

a % b

b로 나눈 나머지(모듈러스)를 돌려줘요. BigDecimal#divmod 참고.

*(p1)

곱셈이에요.

self ** other → bigdecimal

selfother 거듭제곱한 BigDecimal 값을 돌려줘요.

b = BigDecimal('3.14')
b ** 2              # => 0.98596e1
b ** 2.0            # => 0.98596e1
b ** Rational(2, 1) # => 0.98596e1

관련: BigDecimal#power.

self + value → bigdecimal

selfvalue의 BigDecimal 합을 돌려줘요. 정밀도 참고(Note About Precision).

b = BigDecimal('111111.111') # => 0.111111111e6
b + 2                        # => 0.111113111e6
b + 2.0                      # => 0.111113111e6
b + Rational(2, 1)           # => 0.111113111e6
b + Complex(2, 0)            # => (0.111113111e6+0i)

+big_decimal → self

self를 그대로 돌려줘요.

+BigDecimal(5)  # => 0.5e1
+BigDecimal(-5) # => -0.5e1

self - value → bigdecimal

selfvalue의 차를 돌려줘요.

b = BigDecimal('333333.333') # => 0.333333333e6
b - 2                        # => 0.333331333e6
b - 2.0                      # => 0.333331333e6
b - Rational(2, 1)           # => 0.333331333e6
b - Complex(2, 0)            # => (0.333331333e6+0i)

-self → bigdecimal

self의 부호를 바꾼 값을 돌려줘요.

b0 = BigDecimal('1.5')
b1 = -b0 # => -0.15e1
b2 = -b1 # => 0.15e1

a / b → bigdecimal

지정한 값으로 나눠요. 결과 정밀도는 더 큰 피연산자의 정밀도이지만, 최소 2*Float::DIG예요. BigDecimal#div, BigDecimal#quo 참고.

self < other → true or false / self <= other → true or false / self > other → true or false / self >= other → true or false

selfother보다 작은지(또는 이하, 초과, 이상) 여부를 돌려줘요. 비교할 수 없으면 예외를 던져요.

b = BigDecimal('1.5') # => 0.15e1
b < 2                 # => true
b < 2.0               # => true
b < Rational(2, 1)    # => true
b < 1.5               # => false

<=>(p1)

비교 연산자예요. a <=> ba == b면 0, a > b면 1, a < b면 -1이에요.

==(p1) / ===(p1) / eql?(p1)

값 동등성을 검사해요. ==, ===, eql? 모두 BigDecimal에서 같은 구현이에요. 비교를 위해 값을 강제 변환할 수 있어요.

BigDecimal('1.0') == 1.0  #=> true

_dump → string

self의 마샬링을 나타내는 문자열을 돌려줘요. Marshal 모듈 참고.

inf = BigDecimal('Infinity') # => Infinity
dumped = inf._dump           # => "9:Infinity"
BigDecimal._load(dumped)     # => Infinity

abs → bigdecimal

self의 절댓값을 돌려줘요.

BigDecimal('5').abs  # => 0.5e1
BigDecimal('-3').abs # => 0.3e1

add(value, ndigits) → new_bigdecimal

selfvalue의 합을 ndigits 소수 자릿수 정밀도로 돌려줘요. ndigits가 합의 유효 자릿수보다 작으면 현재 반올림 모드(BigDecimal.mode)에 따라 그 자릿수로 반올림해요.

# 반올림 모드 설정.
BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
b = BigDecimal('111111.111')
b.add(1, 0)               # => 0.111112111e6
b.add(1, 3)               # => 0.111e6
b.add(1, 6)               # => 0.111112e6
b.add(1, 15)              # => 0.111112111e6
b.add(1.0, 15)            # => 0.111112111e6
b.add(Rational(1, 1), 15) # => 0.111112111e6

as_json(*)

BigDecimal#as_jsonBigDecimal.json_create로 BigDecimal 객체를 직렬화·역직렬화할 수 있어요. as_jsonself를 직렬화해 2요소 해시를 돌려줘요.

require 'json/add/bigdecimal'
x = BigDecimal(2).as_json             # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}
y = BigDecimal(2.0, 4).as_json        # => {"json_class"=>"BigDecimal", "b"=>"36:0.2e1"}
z = BigDecimal(Complex(2, 0)).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}

BigDecimal.json_create는 그 해시로부터 BigDecimal 객체를 만들고, JSON.create는 역직렬화해요.

BigDecimal.json_create(x) # => 0.2e1
# File ext/json/lib/json/add/bigdecimal.rb, line 35
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'b'            => _dump,
  }
end

ceil(n)

값보다 크거나 같은 가장 작은 정수를 BigDecimal로 돌려줘요. n이 양수면 결과의 소수 부분이 그 자릿수를 넘지 않고, 음수면 소수점 왼쪽으로 그만큼이 0이 돼요.

BigDecimal('3.14159').ceil #=> 4
BigDecimal('-9.1').ceil #=> -9
BigDecimal('3.14159').ceil(3) #=> 3.142
BigDecimal('13345.234').ceil(-2) #=> 13400.0

clone() / dup()

복제예요.

coerce(p1)

Ruby 타입 강제 변환을 지원해요. 기본적으로 활성화돼 있지 않지만, 다른 객체가 BigDecimal로 강제 변환될 수 있으면 + * / - 같은 이항 연산을 BigDecimal과 다른 타입의 객체에 수행할 수 있어요.

a = BigDecimal("1.0")
b = a / 2.0 #=> 0.5

문자열을 BigDecimal로 강제 변환하는 것은 기본적으로 지원되지 않아요(빌드 시 특수 컴파일 옵션이 필요해요).

div(value) → integer / div(value, digits) → bigdecimal or integer

지정한 값으로 나눠요. digits를 지정하고 결과의 유효 자릿수보다 작으면 그 자릿수로 반올림해요(BigDecimal.mode 기준). digits가 0이면 / 연산자나 quo와 같아요. digits를 생략하면 결과는 정수예요(Float#div에 비유, BigDecimal#divmod 참고). BigDecimal#/, BigDecimal#quo 참고.

a = BigDecimal("4")
b = BigDecimal("3")

a.div(b, 3)  # => 0.133e1

a.div(b, 0)  # => 0.1333333333333333333e1
a / b        # => 0.1333333333333333333e1
a.quo(b)     # => 0.1333333333333333333e1

a.div(b)     # => 1

divmod(value)

지정한 값으로 나눠 몫과 나머지를 BigDecimal로 돌려줘요. 몫은 -∞ 방향으로 반올림돼요.

require 'bigdecimal'

a = BigDecimal("42")
b = BigDecimal("9")

q, m = a.divmod(b)

c = q * b + m

a == c  #=> true

q(a/b).floor이고, 나머지는 q * b에 더해 a가 되도록 하는 값이에요.

exponent()

BigDecimal 숫자의 지수를 Integer로 돌려줘요. 숫자를 0.xxxxxx*10**n(xxxxxx는 앞에 0이 없는 숫자 문자열)으로 표현할 수 있다면 n이 지수예요.

finite?()

값이 유한(IS NaN도 무한도 아님)이면 true.

fix()

숫자의 정수 부분을 BigDecimal로 돌려줘요.

floor(n)

값보다 작거나 같은 가장 큰 정수를 BigDecimal로 돌려줘요. n에 관한 동작은 ceil과 같아요.

BigDecimal('3.14159').floor #=> 3
BigDecimal('-9.1').floor #=> -10
BigDecimal('3.14159').floor(3) #=> 3.141
BigDecimal('13345.234').floor(-2) #=> 13300.0

frac()

숫자의 소수 부분을 BigDecimal로 돌려줘요.

hash → integer

self의 정수 해시 값을 돌려줘요. 부호, 소수 부분, 지수가 모두 같은 두 BigDecimal만 같은 해시 값을 가져요.

infinite?()

값이 유한이면 nil, -Infinity면 -1, +Infinity면 +1을 돌려줘요.

inspect()

self의 문자열 표현을 돌려줘요.

BigDecimal("1234.5678").inspect
  #=> "0.12345678e4"

modulo(b)

b로 나눈 나머지를 돌려줘요. BigDecimal#divmod 참고.

mult(other, ndigits) → bigdecimal

selfvalue의 곱을 ndigits 소수 자릿수 정밀도로 돌려줘요. ndigits가 유효 자릿수보다 작으면 현재 반올림 모드로 반올림해요.

BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
b = BigDecimal('555555.555')
b.mult(3, 0)              # => 0.1666666665e7
b.mult(3, 3)              # => 0.167e7
b.mult(3, 6)              # => 0.166667e7
b.mult(3, 15)             # => 0.1666666665e7
b.mult(3.0, 0)            # => 0.1666666665e7
b.mult(Rational(3, 1), 0) # => 0.1666666665e7
b.mult(Complex(3, 0), 0)  # => (0.1666666665e7+0.0i)

n_significant_digits → integer

self의 십진 유효 자릿수를 돌려줘요.

BigDecimal("0").n_significant_digits         # => 0
BigDecimal("1").n_significant_digits         # => 1
BigDecimal("1.1").n_significant_digits       # => 2
BigDecimal("3.1415").n_significant_digits    # => 5
BigDecimal("-1e20").n_significant_digits     # => 1
BigDecimal("1e-20").n_significant_digits     # => 1
BigDecimal("Infinity").n_significant_digits  # => 0
BigDecimal("-Infinity").n_significant_digits # => 0
BigDecimal("NaN").n_significant_digits       # => 0

nan?()

값이 NaN이면 true.

nonzero?()

값이 0이 아니면 self, 0이면 nil을 돌려줘요.

power(n) / power(n, prec)

값을 n 거듭제곱해요. n은 Integer여야 해요. ** 연산자로도 쓸 수 있어요.

precision → integer

self의 십진 자릿수를 돌려줘요.

BigDecimal("0").precision         # => 0
BigDecimal("1").precision         # => 1
BigDecimal("1.1").precision       # => 2
BigDecimal("3.1415").precision    # => 5
BigDecimal("-1e20").precision     # => 21
BigDecimal("1e-20").precision     # => 20
BigDecimal("Infinity").precision  # => 0
BigDecimal("-Infinity").precision # => 0
BigDecimal("NaN").precision       # => 0

precision_scale → [integer, integer]

2요소 배열을 돌려줘요. 첫 항목은 BigDecimal#precision의 결과, 둘째는 BigDecimal#scale의 결과예요.

precs → array

플랫폼 의존적 내부 저장 속성을 나타내는 Integer 두 개의 배열을 돌려줘요. 더 이상 사용하지 않아요(deprecated). 과학적 표기법의 유효 자릿수는 BigDecimal#n_significant_digits, 십진 표기법의 자릿수는 BigDecimal#precision을 쓰세요.

quo(value) → bigdecimal / quo(value, digits) → bigdecimal

지정한 값으로 나눠요. digits를 지정하고 결과의 유효 자릿수보다 작으면 BigDecimal.mode의 반올림 모드에 따라 반올림해요. digits가 0이거나 생략되면 / 연산자와 같아요. BigDecimal#/, BigDecimal#div 참고.

remainder(value)

값으로 나눈 나머지를 돌려줘요. x.remainder(y)x-y*(x/y).truncate를 뜻해요.

round(n, mode)

기본적으로 가장 가까운 정수로 반올림해요. n을 주면 결과가 BigDecimal, 주지 않으면 Integer예요.

BigDecimal('3.14159').round #=> 3
BigDecimal('8.7').round #=> 9
BigDecimal('-9.9').round #=> -10

BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
BigDecimal('3.14159').round.class.name #=> "Integer"

n이 양수면 소수 부분이 그 자릿수를 넘지 않고, 음수면 소수점 왼쪽 그만큼이 0이 되며 반환값은 Integer예요. mode 인자로 반올림 방식을 정할 수 있어요(BigDecimal.mode 참고).

BigDecimal('3.14159').round(3) #=> 3.142
BigDecimal('13345.234').round(-2) #=> 13300

scale → integer

self에서 소수점 뒤의 자릿수를 돌려줘요.

BigDecimal("0").scale         # => 0
BigDecimal("1").scale         # => 0
BigDecimal("1.1").scale       # => 1
BigDecimal("3.1415").scale    # => 4
BigDecimal("Infinity").scale  # => 0
BigDecimal("NaN").scale       # => 0

sign()

값의 부호를 돌려줘요. >0이면 양수 값, <0이면 음수 값을 돌려줘요. 0에 대해서도 마찬가지로 동작해요 — 양의 0(BigDecimal('0'))은 양수 값을, 음의 0(BigDecimal('-0'))은 음수 값을 돌려줘요. 반환되는 구체적인 값은 BigDecimal의 타입과 부호를 나타내요: NaN이면 SIGN_NaN, +0이면 SIGN_POSITIVE_ZERO, -0이면 SIGN_NEGATIVE_ZERO, +Infinity면 SIGN_POSITIVE_INFINITE, -Infinity면 SIGN_NEGATIVE_INFINITE, 양수면 SIGN_POSITIVE_FINITE, 음수면 SIGN_NEGATIVE_FINITE.

split()

BigDecimal을 네 부분으로 나눠 배열로 돌려줘요.

  • 첫 값은 부호로, -1 또는 1(또는 NaN이면 0)이에요.
  • 둘째는 앞에 0이 없는 유효 숫자 문자열이에요.
  • 셋째는 연산에 쓰는 밑(현재 항상 10)의 Integer예요.
  • 넷째는 Integer 지수예요.

0.xxxxxx*10**n으로 표현된다면 xxxxxx가 유효 숫자 문자열이고 n이 지수예요. 이 값들로 BigDecimal을 float로 변환할 수 있어요.

sign, significant_digits, base, exponent = a.split
f = sign * "0.#{significant_digits}".to_f * (base ** exponent)

(BigDecimal을 Float로 변환하는 더 편리한 방법은 to_f 메서드예요.)

sqrt(n)

값의 제곱근을 돌려줘요. 결과는 적어도 n개의 유효 자릿수를 가져요.

sub(value, digits) → bigdecimal

지정한 값을 뺄셈해요. digits를 지정하고 결과의 유효 자릿수보다 작으면 BigDecimal.mode에 따라 반올림해요.

c = a.sub(b,n)

to_d → bigdecimal

self를 돌려줘요.

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_d                       # => 0.314e1
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 110
def to_d
  self
end

to_digits → string

BigDecimal을 "nnnnnn.mmm" 형태의 문자열로 변환해요. 더 이상 사용하지 않아요(deprecated); BigDecimal#to_s("F")를 쓰세요.

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_digits                  # => "3.14"

to_f()

BigDecimal과 대략 같은 값을 갖는 새 Float 객체를 돌려줘요. 이진 Float 연산의 일반적인 정밀도 한계와 내장 오차가 적용돼요.

to_i() / to_int()

값을 Integer로 돌려줘요. BigDecimal이 무한대나 NaN이면 FloatDomainError를 던져요.

to_json(*args)

self를 나타내는 JSON 문자열을 돌려줘요.

require 'json/add/bigdecimal'
puts BigDecimal(2).to_json
# {"json_class":"BigDecimal","b":"27:0.2e1"}
# File ext/json/lib/json/add/bigdecimal.rb, line 55
def to_json(*args)
  as_json.to_json(*args)
end

to_r()

BigDecimal을 Rational로 변환해요.

to_s(s)

값을 문자열로 변환해요. 기본 형식은 0.xxxxEnn이에요. 선택 인자 s는 정수 하나이거나, 선택적 '+'' ' 뒤에 선택적 숫자, 선택적 'E''F'로 구성돼요.

  • s 시작에 '+'가 있으면 양수 값 앞에 '+'가 붙어요.
  • s 시작에 공백이 있으면 양수 값 앞에 공백이 붙어요.
  • s에 숫자가 있으면 소수점부터 바깥으로 세면서 그 자릿수마다 공백이 들어가요.
  • s'E'로 끝나면 공학 표기법(0.xxxxEnn)을 쓰고, 'F'로 끝나면 일반 부동소수점 표기법을 써요.
BigDecimal('-1234567890123.45678901234567890').to_s('5F')
  #=> '-123 45678 90123.45678 90123 45678 9'

BigDecimal('1234567890123.45678901234567890').to_s('+8F')
  #=> '+12345 67890123.45678901 23456789'

BigDecimal('1234567890123.45678901234567890').to_s(' F')
  #=> ' 1234567890123.4567890123456789'

truncate(n)

기본적으로 가장 가까운 정수로 자르고 결과를 BigDecimal로 돌려줘요. n에 관한 동작은 ceil과 같아요.

BigDecimal('3.14159').truncate #=> 3
BigDecimal('8.7').truncate #=> 8
BigDecimal('-9.9').truncate #=> -9
BigDecimal('3.14159').truncate(3) #=> 3.141
BigDecimal('13345.234').truncate(-2) #=> 13300.0

zero?()

값이 0이면 true.

더 알아보기

  • require 'bigdecimal/math'BigMath 모듈의 고정밀 삼각함수·지수·로그 함수를 쓸 수 있어요.
  • bigdecimal/utilto_d로 일반 숫자·문자열을 BigDecimal로 쉽게 변환할 수 있어요.