BigDecimal 類別

BigDecimal 提供任意精度的浮點數十進位算術。

簡介

Ruby 提供內建支援,用於任意精度的整數算術。

例如

42**13  #=>   1265437718438866624512

BigDecimal 提供類似的支援,用於非常大或非常精確的浮點數。

十進位算術也適用於一般計算,因為它提供人們預期的正確答案,而正常的二進位浮點數算術通常會因為 10 進位和 2 進位之間的轉換,而產生細微的誤差。

例如,請嘗試

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

並與以下輸出的對比

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

關於精度的說明

對於使用 BigDecimal 和另一個 value 進行的計算,結果的精度取決於 value 的類型

準確十進位算術的特殊功能

因為 BigDecimal 比一般的二進制浮點算術更準確,因此需要一些特殊值。

無限大

BigDecimal 有時需要傳回無限大,例如當你將一個值除以零時。

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

你可以使用字串 'Infinity''+Infinity''-Infinity' (大小寫敏感) 來表示無限大的數字給 BigDecimal

非數字

當運算結果為未定義值時,會傳回特殊值 NaN(代表「非數字」)。

範例

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

你也可以建立未定義值。

NaN 永遠不會被視為與任何其他值相同,即使是 NaN 本身。

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

正負零

如果運算結果為一個值,而這個值太小,無法在目前指定的精度限制內表示為 BigDecimal,則必須傳回零。

如果這個太小而無法表示的值為負值,則傳回 BigDecimal 值負零。

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

如果這個值為正值,則傳回正零值。

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

(請參閱 BigDecimal.mode,了解如何指定精度限制。)

請注意,在比較時,-0.00.0 被視為相同。

另請注意,在數學中,沒有特別的負零或正零概念;真正的數學零沒有符號。

bigdecimal/util

當你需要 bigdecimal/util 時,to_d 方法將會在 BigDecimal 和原生 IntegerFloatRationalString 類別中提供。

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 gem 提供。若要讓這些方法可用

require 'json/add/bigdecimal'

版權所有 © 2002 by Shigeo Kobayashi <[email protected]>。

BigDecimal 在 Ruby 和 2 條款 BSD 授權下發布。有關詳細資訊,請參閱 LICENSE.txt。

由 mrkn <[email protected]> 和 ruby-core 成員維護。

由 zzak <[email protected]>、mathew <[email protected]> 和許多其他貢獻者撰寫文件。

常數

BASE

內部計算中使用的基底值。在 32 位元系統上,BASE 為 10000,表示計算是以 4 位數為一組進行的。(如果更大,BASE**2 就無法放入 32 位元,因此無法保證兩個組永遠可以在不溢出的情況下相乘。)

EXCEPTION_ALL

決定溢出、下溢或零除是否會導致引發例外。請參閱 BigDecimal.mode

EXCEPTION_INFINITY

決定當運算結果為無限大時會發生什麼事。請參閱 BigDecimal.mode

EXCEPTION_NaN

決定當運算結果為非數字 (NaN) 時會發生什麼事。請參閱 BigDecimal.mode

EXCEPTION_OVERFLOW

決定當運算結果為溢出 (結果太大而無法表示) 時會發生什麼事。請參閱 BigDecimal.mode

EXCEPTION_UNDERFLOW

決定當運算結果為下溢 (結果太小而無法表示) 時會發生什麼事。請參閱 BigDecimal.mode

EXCEPTION_ZERODIVIDE

決定當執行除以零時會發生什麼事。請參閱 BigDecimal.mode

INFINITY

特殊值常數

NAN
ROUND_CEILING

朝 + 無限大進位。請參閱 BigDecimal.mode

ROUND_DOWN

表示值應四捨五入至零。請參閱 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

表示值應四捨五入至遠離零。請參閱 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 函式庫的版本

公共類別方法

_load(p1) 按一下以切換來源

用於提供封送支援的內部方法。請參閱 Marshal 模組。

static VALUE
BigDecimal_load(VALUE self, VALUE str)
{
    ENTER(2);
    Real *pv;
    unsigned char *pch;
    unsigned char ch;
    unsigned long m=0;

    pch = (unsigned char *)StringValueCStr(str);
    /* First get max prec */
    while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
        if(!ISDIGIT(ch)) {
            rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
        }
        m = m*10 + (unsigned long)(ch-'0');
    }
    if (m > VpBaseFig()) m -= VpBaseFig();
    GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
    m /= VpBaseFig();
    if (m && pv->MaxPrec > m) {
        pv->MaxPrec = m+1;
    }
    return VpCheckGetValue(pv);
}
double_fig → integer 按一下以切換來源

傳回 Float 物件允許擁有的數字數量;結果取決於系統

BigDecimal.double_fig # => 16
static inline VALUE
BigDecimal_double_fig(VALUE self)
{
    return INT2FIX(VpDblFig());
}
interpret_loosely(p1) 按一下以切換來源
static VALUE
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
{
    char const *c_str = StringValueCStr(str);
    Real *vp = VpNewRbClass(0, c_str, klass, false, true);
    if (!vp)
        return Qnil;
    else
        return VpCheckGetValue(vp);
}
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)的任何限制。

static VALUE
BigDecimal_limit(int argc, VALUE *argv, VALUE self)
{
    VALUE  nFig;
    VALUE  nCur = SIZET2NUM(VpGetPrecLimit());

    if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
        int nf;
        if (NIL_P(nFig)) return nCur;
        nf = NUM2INT(nFig);
        if (nf < 0) {
            rb_raise(rb_eArgError, "argument must be positive");
        }
        VpSetPrecLimit(nf);
    }
    return nCur;
}
mode(mode, setting = nil) → integer 按一下以切換來源

傳回表示例外處理和捨入的模式設定的整數。

這些模式控制例外處理

  • BigDecimal::EXCEPTION_NaN。

  • BigDecimal::EXCEPTION_INFINITY。

  • BigDecimal::EXCEPTION_UNDERFLOW。

  • BigDecimal::EXCEPTION_OVERFLOW。

  • BigDecimal::EXCEPTION_ZERODIVIDE。

  • BigDecimal::EXCEPTION_ALL。

setting 的例外處理值

  • true:將指定的 mode 設定為 true

  • false:將指定的 mode 設定為 false

  • nil:不修改模式設定。

您可以使用 BigDecimal.save_exception_mode 方法暫時變更,然後自動還原例外模式。

為了清楚起見,以下部分範例會從將所有例外模式設定為 false 開始。

此模式控制執行捨入的方式

  • BigDecimal::ROUND_MODE

您可以使用 BigDecimal.save_rounding_mode 方法暫時變更,然後自動還原捨入模式。

NaN

模式 BigDecimal::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

無限大

模式 BigDecimal::EXCEPTION_INFINITY 控制在建立 BigDecimal Infinity 或 -Infinity 時的行為。設定

  • false(預設):傳回 BigDecimal('Infinity')BigDecimal('-Infinity')

  • true:引發 FloatDomainError

範例

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

下溢

模式 BigDecimal::EXCEPTION_UNDERFLOW 控制在發生 BigDecimal 下溢時行為。設定

  • false(預設):傳回 BigDecimal('0')BigDecimal('-Infinity')

  • true:引發 FloatDomainError

範例

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

上溢

模式 BigDecimal::EXCEPTION_OVERFLOW 控制在發生 BigDecimal 上溢時行為。設定

  • false(預設):傳回 BigDecimal('Infinity')BigDecimal('-Infinity')

  • true:引發 FloatDomainError

範例

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

零除

模式 BigDecimal::EXCEPTION_ZERODIVIDE 控制在發生零除時行為。設定

  • false(預設):傳回 BigDecimal('Infinity')BigDecimal('-Infinity')

  • true:引發 FloatDomainError

範例

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

所有例外

模式 BigDecimal::EXCEPTION_ALL 控制以上所有

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

捨入

模式 BigDecimal::ROUND_MODE 控制執行捨入的方式;其 setting 值為

  • ROUND_UP:捨入至遠離零。別名為 :up

  • ROUND_DOWN:捨入至接近零。別名為 :down:truncate

  • ROUND_HALF_UP:捨入至最接近的鄰近值;如果鄰近值距離相等,則捨入至遠離零。別名為 :half_up:default

  • ROUND_HALF_DOWN:朝最近的鄰居四捨五入;如果鄰居等距,則朝零四捨五入。別名為 :half_down

  • ROUND_HALF_EVEN(銀行家四捨五入):朝最近的鄰居四捨五入;如果鄰居等距,則朝偶數鄰居四捨五入。別名為 :half_even:banker

  • ROUND_CEILING:朝正無窮大四捨五入。別名為 :ceiling:ceil

  • ROUND_FLOOR:朝負無窮大四捨五入。別名為 :floor:

static VALUE
BigDecimal_mode(int argc, VALUE *argv, VALUE self)
{
    VALUE which;
    VALUE val;
    unsigned long f,fo;

    rb_scan_args(argc, argv, "11", &which, &val);
    f = (unsigned long)NUM2INT(which);

    if (f & VP_EXCEPTION_ALL) {
        /* Exception mode setting */
        fo = VpGetException();
        if (val == Qnil) return INT2FIX(fo);
        if (val != Qfalse && val!=Qtrue) {
            rb_raise(rb_eArgError, "second argument must be true or false");
            return Qnil; /* Not reached */
        }
        if (f & VP_EXCEPTION_INFINITY) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) :
                        (fo & (~VP_EXCEPTION_INFINITY))));
        }
        fo = VpGetException();
        if (f & VP_EXCEPTION_NaN) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) :
                        (fo & (~VP_EXCEPTION_NaN))));
        }
        fo = VpGetException();
        if (f & VP_EXCEPTION_UNDERFLOW) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) :
                        (fo & (~VP_EXCEPTION_UNDERFLOW))));
        }
        fo = VpGetException();
        if(f & VP_EXCEPTION_ZERODIVIDE) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) :
                        (fo & (~VP_EXCEPTION_ZERODIVIDE))));
        }
        fo = VpGetException();
        return INT2FIX(fo);
    }
    if (VP_ROUND_MODE == f) {
        /* Rounding mode setting */
        unsigned short sw;
        fo = VpGetRoundMode();
        if (NIL_P(val)) return INT2FIX(fo);
        sw = check_rounding_mode(val);
        fo = VpSetRoundMode(sw);
        return INT2FIX(fo);
    }
    rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid");
    return Qnil;
}
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

static VALUE
BigDecimal_save_exception_mode(VALUE self)
{
    unsigned short const exception_mode = VpGetException();
    int state;
    VALUE ret = rb_protect(rb_yield, Qnil, &state);
    VpSetException(exception_mode);
    if (state) rb_jump_tag(state);
    return ret;
}
save_limit { ... } 按一下以切換來源

執行提供的區塊,但保留精確度限制

BigDecimal.limit(100)
puts BigDecimal.limit
BigDecimal.save_limit do
    BigDecimal.limit(200)
    puts BigDecimal.limit
end
puts BigDecimal.limit
static VALUE
BigDecimal_save_limit(VALUE self)
{
    size_t const limit = VpGetPrecLimit();
    int state;
    VALUE ret = rb_protect(rb_yield, Qnil, &state);
    VpSetPrecLimit(limit);
    if (state) rb_jump_tag(state);
    return ret;
}
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

static VALUE
BigDecimal_save_rounding_mode(VALUE self)
{
    unsigned short const round_mode = VpGetRoundMode();
    int state;
    VALUE ret = rb_protect(rb_yield, Qnil, &state);
    VpSetRoundMode(round_mode);
    if (state) rb_jump_tag(state);
    return ret;
}

公開實例方法

a % b 按一下以切換來源

傳回除以 b 的餘數。

請參閱 BigDecimal#divmod

static VALUE
BigDecimal_mod(VALUE self, VALUE r) 
別名也為:modulo
*(p1) 按一下以切換來源
static VALUE
BigDecimal_mult(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    if (RB_TYPE_P(r, T_FLOAT)) {
        b = GetVpValueWithPrec(r, 0, 1);
    }
    else if (RB_TYPE_P(r, T_RATIONAL)) {
        b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
    }
    else {
        b = GetVpValue(r,0);
    }

    if (!b) return DoSomeOne(self, r, '*');
    SAVE(b);

    mx = a->Prec + b->Prec;
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
    VpMult(c, a, b);
    return VpCheckGetValue(c);
}
self ** other → bigdecimal 按一下以切換來源

傳回 self 乘方 other 的 BigDecimal 值

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

相關:BigDecimal#power

static VALUE
BigDecimal_power_op(VALUE self, VALUE exp)
{
    return BigDecimal_power(1, &exp, self);
}
self + value → bigdecimal 按一下以切換來源

傳回 selfvalue 的 BigDecimal 總和

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)

請參閱 關於精確度的注意事項

static VALUE
BigDecimal_add(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    if (RB_TYPE_P(r, T_FLOAT)) {
        b = GetVpValueWithPrec(r, 0, 1);
    }
    else if (RB_TYPE_P(r, T_RATIONAL)) {
        b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
    }
    else {
        b = GetVpValue(r, 0);
    }

    if (!b) return DoSomeOne(self,r,'+');
    SAVE(b);

    if (VpIsNaN(b)) return b->obj;
    if (VpIsNaN(a)) return a->obj;

    mx = GetAddSubPrec(a, b);
    if (mx == (size_t)-1L) {
        GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
        VpAddSub(c, a, b, 1);
    }
    else {
        GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
        if (!mx) {
            VpSetInf(c, VpGetSign(a));
        }
        else {
            VpAddSub(c, a, b, 1);
        }
    }
    return VpCheckGetValue(c);
}
+big_decimal → self 按一下以切換來源

傳回 self

+BigDecimal(5)  # => 0.5e1
+BigDecimal(-5) # => -0.5e1
static VALUE
BigDecimal_uplus(VALUE self)
{
    return self;
}
self - value → bigdecimal 按一下以切換來源

傳回 selfvalue 的 BigDecimal 差

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)

請參閱 關於精確度的注意事項

static VALUE
BigDecimal_sub(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self,1));
    if (RB_TYPE_P(r, T_FLOAT)) {
        b = GetVpValueWithPrec(r, 0, 1);
    }
    else if (RB_TYPE_P(r, T_RATIONAL)) {
        b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
    }
    else {
        b = GetVpValue(r,0);
    }

    if (!b) return DoSomeOne(self,r,'-');
    SAVE(b);

    if (VpIsNaN(b)) return b->obj;
    if (VpIsNaN(a)) return a->obj;

    mx = GetAddSubPrec(a,b);
    if (mx == (size_t)-1L) {
        GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
        VpAddSub(c, a, b, -1);
    }
    else {
        GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
        if (!mx) {
            VpSetInf(c,VpGetSign(a));
        }
        else {
            VpAddSub(c, a, b, -1);
        }
    }
    return VpCheckGetValue(c);
}
-self → bigdecimal 按一下以切換來源

傳回 self 的 BigDecimal 負數

b0 = BigDecimal('1.5')
b1 = -b0 # => -0.15e1
b2 = -b1 # => 0.15e1
static VALUE
BigDecimal_neg(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    GUARD_OBJ(a, GetVpValue(self, 1));
    GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
    VpAsgn(c, a, -1);
    return VpCheckGetValue(c);
}
a / b → bigdecimal 按一下以切換來源

除以指定的值。

結果精度會是較大運算元的精度,但其最小值是 2*Float::DIG。

請參閱 BigDecimal#div。請參閱 BigDecimal#quo

static VALUE
BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{
    ENTER(5);
    Real *c=NULL, *res=NULL, *div = NULL;
    r = BigDecimal_divide(self, r, &c, &res, &div);
    if (!NIL_P(r)) return r; /* coerced by other */
    SAVE(c); SAVE(res); SAVE(div);
    /* a/b = c + r/b */
    /* c xxxxx
       r 00000yyyyy  ==> (y/b)*BASE >= HALF_BASE
     */
    /* Round */
    if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
        VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
    }
    return VpCheckGetValue(c);
}
self < other → true 或 false 按一下以切換來源

如果 self 小於 other,則傳回 true,否則傳回 false

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

如果無法進行比較,則會引發例外狀況。

static VALUE
BigDecimal_lt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '<');
}
self <= other → true 或 false 按一下以切換來源

如果 self 小於或等於 other,則傳回 true,否則傳回 false

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

如果無法進行比較,則會引發例外狀況。

static VALUE
BigDecimal_le(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'L');
}
<=>(p1) 按一下以切換來源

比較運算子。如果 a == b,則 a <=> b 為 0;如果 a > b,則為 1;如果 a < b,則為 -1。

static VALUE
BigDecimal_comp(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '*');
}
==(p1) 按一下以切換來源

測試值相等性;如果值相等,則傳回 true。

對於 BigDecimal,== 和 === 運算子以及 eql? 方法具有相同的實作。

可以強制轉換值以執行比較

BigDecimal('1.0') == 1.0  #=> true
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}
別名:===eql?
===(p1)

測試值相等性;如果值相等,則傳回 true。

對於 BigDecimal,== 和 === 運算子以及 eql? 方法具有相同的實作。

可以強制轉換值以執行比較

BigDecimal('1.0') == 1.0  #=> true
別名:==
self > other → true 或 false 按一下以切換來源

如果 self 大於 other,則傳回 true,否則傳回 false

b = BigDecimal('1.5')
b > 1              # => true
b > 1.0            # => true
b > Rational(1, 1) # => true
b > 2              # => false

如果無法進行比較,則會引發例外狀況。

static VALUE
BigDecimal_gt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '>');
}
self >= other → true 或 false 按一下以切換來源

如果 self 大於或等於 other,則傳回 true,否則傳回 false

b = BigDecimal('1.5')
b >= 1              # => true
b >= 1.0            # => true
b >= Rational(1, 1) # => true
b >= 1.5            # => true
b > 2               # => false

如果無法進行比較,則會引發例外狀況。

static VALUE
BigDecimal_ge(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'G');
}
_dump → 字串 按一下以切換來源

傳回表示 self 封送的字串。請參閱模組 Marshal

inf = BigDecimal('Infinity') # => Infinity
dumped = inf._dump           # => "9:Infinity"
BigDecimal._load(dumped)     # => Infinity
static VALUE
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *vp;
    char *psz;
    VALUE dummy;
    volatile VALUE dump;
    size_t len;

    rb_scan_args(argc, argv, "01", &dummy);
    GUARD_OBJ(vp,GetVpValue(self, 1));
    dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
    psz = RSTRING_PTR(dump);
    snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
    len = strlen(psz);
    VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
    rb_str_resize(dump, strlen(psz));
    return dump;
}
abs → bigdecimal 按一下以切換來源

傳回 self 的 BigDecimal 絕對值

BigDecimal('5').abs  # => 0.5e1
BigDecimal('-3').abs # => 0.3e1
static VALUE
BigDecimal_abs(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpAsgn(c, a, 1);
    VpChangeSign(c, 1);
    return VpCheckGetValue(c);
}
add(value, ndigits) → new_bigdecimal 按一下以切換來源

傳回 selfvalue 的 BigDecimal 總和,其精度為 ndigits 小數位。

ndigits 小於總和中的有效數字位數時,總和會根據目前的捨入模式捨入到該數字位數;請參閱 BigDecimal.mode

範例

# Set the rounding 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
static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = check_int_precision(n);
    if (mx == 0) return BigDecimal_add(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_add(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return VpCheckGetValue(cv);
    }
}
as_json(*) 按一下以切換來源

方法 BigDecimal#as_jsonBigDecimal.json_create 可用於序列化和反序列化 BigDecimal 物件;請參閱 Marshal

方法 BigDecimal#as_json 會序列化 self,傳回代表 self 的 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"}

方法 JSON.create 會反序列化此類雜湊,傳回 BigDecimal 物件

BigDecimal.json_create(x) # => 0.2e1
BigDecimal.json_create(y) # => 0.2e1
BigDecimal.json_create(z) # => 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

BigDecimal('3.14159').ceil #=> 4
BigDecimal('-9.1').ceil #=> -9

如果指定 n 且為正數,結果的小數部分不會超過該數字位數。

如果指定 n 且為負數,結果的小數點左方至少會有該數字位數為 0。

BigDecimal('3.14159').ceil(3) #=> 3.142
BigDecimal('13345.234').ceil(-2) #=> 13400.0
static VALUE
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
        iLoc = 0;
    } else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
    if (argc == 0) {
        return BigDecimal_to_i(VpCheckGetValue(c));
    }
    return VpCheckGetValue(c);
}
clone() 按一下以切換來源
static VALUE
BigDecimal_clone(VALUE self)
{
  return self;
}
別名:dup
coerce(p1) 按一下以切換來源

coerce 方法提供 Ruby 型別強制轉換的支援。它並未預設啟用。

這表示二元運算,例如 + * / 或 -,通常可以在 BigDecimal 和另一種型別的物件上執行,如果另一個物件可以強制轉換為 BigDecimal 值。

例如:

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

請注意,預設不支援將 String 強制轉換為 BigDecimal;它需要在建置 Ruby 時使用特殊的編譯時期選項。

static VALUE
BigDecimal_coerce(VALUE self, VALUE other)
{
    ENTER(2);
    VALUE obj;
    Real *b;

    if (RB_TYPE_P(other, T_FLOAT)) {
        GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
        obj = rb_assoc_new(VpCheckGetValue(b), self);
    }
    else {
        if (RB_TYPE_P(other, T_RATIONAL)) {
            Real* pv = DATA_PTR(self);
            GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
        }
        else {
            GUARD_OBJ(b, GetVpValue(other, 1));
        }
        obj = rb_assoc_new(b->obj, self);
    }

    return obj;
}
div(value) → integer 按一下以切換來源
div(value, digits) → bigdecimal 或 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
static VALUE
BigDecimal_div3(int argc, VALUE *argv, VALUE self)
{
    VALUE b,n;

    rb_scan_args(argc, argv, "11", &b, &n);

    return BigDecimal_div2(self, b, n);
}
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 的值。

static VALUE
BigDecimal_divmod(VALUE self, VALUE r)
{
    ENTER(5);
    Real *div = NULL, *mod = NULL;

    if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
        SAVE(div); SAVE(mod);
        return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
    }
    return DoSomeOne(self,r,rb_intern("divmod"));
}
dup()
別名為:clone
eql?(p1)

測試值相等性;如果值相等,則傳回 true。

對於 BigDecimal,== 和 === 運算子以及 eql? 方法具有相同的實作。

可以強制轉換值以執行比較

BigDecimal('1.0') == 1.0  #=> true
別名:==
exponent() 按一下以切換來源

傳回 BigDecimal 數字的指數,為 Integer

如果數字可以表示為 0.xxxxxx*10**n,其中 xxxxxx 是沒有前導零的數字字串,則 n 為指數。

static VALUE
BigDecimal_exponent(VALUE self)
{
    ssize_t e = VpExponent10(GetVpValue(self, 1));
    return SSIZET2NUM(e);
}
finite?() 按一下以切換來源

如果值是有限的(不是 NaN 或無限大),則傳回 True。

static VALUE
BigDecimal_IsFinite(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsNaN(p)) return Qfalse;
    if (VpIsInf(p)) return Qfalse;
    return Qtrue;
}
fix() 按一下以切換來源

傳回數字的整數部分,為 BigDecimal

static VALUE
BigDecimal_fix(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
    return VpCheckGetValue(c);
}
floor(n) 按一下以切換來源

傳回小於或等於該值的最大的整數,為 BigDecimal

BigDecimal('3.14159').floor #=> 3
BigDecimal('-9.1').floor #=> -10

如果指定 n 且為正數,結果的小數部分不會超過該數字位數。

如果指定 n 且為負數,結果的小數點左方至少會有該數字位數為 0。

BigDecimal('3.14159').floor(3) #=> 3.141
BigDecimal('13345.234').floor(-2) #=> 13300.0
static VALUE
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
        iLoc = 0;
    }
    else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
#ifdef BIGDECIMAL_DEBUG
    VPrint(stderr, "floor: c=%\n", c);
#endif
    if (argc == 0) {
        return BigDecimal_to_i(VpCheckGetValue(c));
    }
    return VpCheckGetValue(c);
}
frac() 按一下以切換來源

傳回數字的小數部分,為 BigDecimal

static VALUE
BigDecimal_frac(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpFrac(c, a);
    return VpCheckGetValue(c);
}
hash → integer 按一下以切換來源

傳回 self 的整數雜湊值。

只有當 BigDecimal 的兩個實例具有相等的下列條件時,它們才具有相同的雜湊值:

  • 符號。

  • 小數部分。

  • 指數。

static VALUE
BigDecimal_hash(VALUE self)
{
    ENTER(1);
    Real *p;
    st_index_t hash;

    GUARD_OBJ(p, GetVpValue(self, 1));
    hash = (st_index_t)p->sign;
    /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
    if(hash == 2 || hash == (st_index_t)-2) {
        hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
        hash += p->exponent;
    }
    return ST2FIX(hash);
}
infinite?() 按一下以切換來源

根據值是有限、-Infinity 或 +Infinity,傳回 nil、-1 或 +1。

static VALUE
BigDecimal_IsInfinite(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsPosInf(p)) return INT2FIX(1);
    if (VpIsNegInf(p)) return INT2FIX(-1);
    return Qnil;
}
inspect() 按一下以切換來源

傳回 self 的字串表示形式。

BigDecimal("1234.5678").inspect
  #=> "0.12345678e4"
static VALUE
BigDecimal_inspect(VALUE self)
{
    ENTER(5);
    Real *vp;
    volatile VALUE str;
    size_t nc;

    GUARD_OBJ(vp, GetVpValue(self, 1));
    nc = VpNumOfChars(vp, "E");

    str = rb_str_new(0, nc);
    VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
    rb_str_resize(str, strlen(RSTRING_PTR(str)));
    return str;
}
modulo(b)

傳回除以 b 的餘數。

請參閱 BigDecimal#divmod

別名:%
mult(other, ndigits) → bigdecimal 按一下以切換來源

傳回 selfvalue 的 BigDecimal 乘積,其精度為 ndigits 小數位數。

ndigits 小於總和中的有效數字位數時,總和會根據目前的捨入模式捨入到該數字位數;請參閱 BigDecimal.mode

範例

# Set the rounding mode.
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)
static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = check_int_precision(n);
    if (mx == 0) return BigDecimal_mult(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_mult(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return VpCheckGetValue(cv);
    }
}
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
static VALUE
BigDecimal_n_significant_digits(VALUE self)
{
    ENTER(1);

    Real *p;
    GUARD_OBJ(p, GetVpValue(self, 1));
    if (VpIsZero(p) || !VpIsDef(p)) {
        return INT2FIX(0);
    }

    ssize_t n = p->Prec;  /* The length of frac without trailing zeros. */
    for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n);
    if (n == 0) return INT2FIX(0);

    DECDIG x;
    int nlz = BASE_FIG;
    for (x = p->frac[0]; x > 0; x /= 10) --nlz;

    int ntz = 0;
    for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;

    ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
    return SSIZET2NUM(n_significant_digits);
}
nan?() 按一下以切換來源

如果值不是數字,則傳回 True。

static VALUE
BigDecimal_IsNaN(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsNaN(p))  return Qtrue;
    return Qfalse;
}
nonzero?() 按一下以切換來源

如果值是非零值,則傳回 self,否則傳回 nil。

static VALUE
BigDecimal_nonzero(VALUE self)
{
    Real *a = GetVpValue(self, 1);
    return VpIsZero(a) ? Qnil : self;
}
power(n) 按一下以切換來源
power(n, prec)

傳回提升至 n 次方的值。

請注意,n 必須是 Integer

也可以當作運算子 ** 使用。

static VALUE
BigDecimal_power(int argc, VALUE*argv, VALUE self)
{
    ENTER(5);
    VALUE vexp, prec;
    Real* exp = NULL;
    Real *x, *y;
    ssize_t mp, ma, n;
    SIGNED_VALUE int_exp;
    double d;

    rb_scan_args(argc, argv, "11", &vexp, &prec);

    GUARD_OBJ(x, GetVpValue(self, 1));
    n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);

    if (VpIsNaN(x)) {
        y = NewZeroWrapLimited(1, n);
        VpSetNaN(y);
        RB_GC_GUARD(y->obj);
        return VpCheckGetValue(y);
    }

  retry:
    switch (TYPE(vexp)) {
      case T_FIXNUM:
        break;

      case T_BIGNUM:
        break;

      case T_FLOAT:
        d = RFLOAT_VALUE(vexp);
        if (d == round(d)) {
            if (FIXABLE(d)) {
                vexp = LONG2FIX((long)d);
            }
            else {
                vexp = rb_dbl2big(d);
            }
            goto retry;
        }
        if (NIL_P(prec)) {
            n += BIGDECIMAL_DOUBLE_FIGURES;
        }
        exp = GetVpValueWithPrec(vexp, 0, 1);
        break;

      case T_RATIONAL:
        if (is_zero(rb_rational_num(vexp))) {
            if (is_positive(vexp)) {
                vexp = INT2FIX(0);
                goto retry;
            }
        }
        else if (is_one(rb_rational_den(vexp))) {
            vexp = rb_rational_num(vexp);
            goto retry;
        }
        exp = GetVpValueWithPrec(vexp, n, 1);
        if (NIL_P(prec)) {
            n += n;
        }
        break;

      case T_DATA:
        if (is_kind_of_BigDecimal(vexp)) {
            VALUE zero = INT2FIX(0);
            VALUE rounded = BigDecimal_round(1, &zero, vexp);
            if (RTEST(BigDecimal_eq(vexp, rounded))) {
                vexp = BigDecimal_to_i(vexp);
                goto retry;
            }
            if (NIL_P(prec)) {
                GUARD_OBJ(y, GetVpValue(vexp, 1));
                n += y->Prec*VpBaseFig();
            }
            exp = DATA_PTR(vexp);
            break;
        }
        /* fall through */
      default:
        rb_raise(rb_eTypeError,
                 "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
                 RB_OBJ_CLASSNAME(vexp));
    }

    if (VpIsZero(x)) {
        if (is_negative(vexp)) {
            y = NewZeroWrapNolimit(1, n);
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        /* (-0) ** (-even_integer)  -> Infinity */
                        VpSetPosInf(y);
                    }
                    else {
                        /* (-0) ** (-odd_integer)  -> -Infinity */
                        VpSetNegInf(y);
                    }
                }
                else {
                    /* (-0) ** (-non_integer)  -> Infinity */
                    VpSetPosInf(y);
                }
            }
            else {
                /* (+0) ** (-num)  -> Infinity */
                VpSetPosInf(y);
            }
            RB_GC_GUARD(y->obj);
            return VpCheckGetValue(y);
        }
        else if (is_zero(vexp)) {
            return VpCheckGetValue(NewOneWrapLimited(1, n));
        }
        else {
            return VpCheckGetValue(NewZeroWrapLimited(1, n));
        }
    }

    if (is_zero(vexp)) {
        return VpCheckGetValue(NewOneWrapLimited(1, n));
    }
    else if (is_one(vexp)) {
        return self;
    }

    if (VpIsInf(x)) {
        if (is_negative(vexp)) {
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        /* (-Infinity) ** (-even_integer) -> +0 */
                        return VpCheckGetValue(NewZeroWrapLimited(1, n));
                    }
                    else {
                        /* (-Infinity) ** (-odd_integer) -> -0 */
                        return VpCheckGetValue(NewZeroWrapLimited(-1, n));
                    }
                }
                else {
                    /* (-Infinity) ** (-non_integer) -> -0 */
                    return VpCheckGetValue(NewZeroWrapLimited(-1, n));
                }
            }
            else {
                return VpCheckGetValue(NewZeroWrapLimited(1, n));
            }
        }
        else {
            y = NewZeroWrapLimited(1, n);
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        VpSetPosInf(y);
                    }
                    else {
                        VpSetNegInf(y);
                    }
                }
                else {
                    /* TODO: support complex */
                    rb_raise(rb_eMathDomainError,
                            "a non-integral exponent for a negative base");
                }
            }
            else {
                VpSetPosInf(y);
            }
            return VpCheckGetValue(y);
        }
    }

    if (exp != NULL) {
        return bigdecimal_power_by_bigdecimal(x, exp, n);
    }
    else if (RB_TYPE_P(vexp, T_BIGNUM)) {
        VALUE abs_value = BigDecimal_abs(self);
        if (is_one(abs_value)) {
            return VpCheckGetValue(NewOneWrapLimited(1, n));
        }
        else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
            if (is_negative(vexp)) {
                y = NewZeroWrapLimited(1, n);
                VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
                return VpCheckGetValue(y);
            }
            else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
                return VpCheckGetValue(NewZeroWrapLimited(-1, n));
            }
            else {
                return VpCheckGetValue(NewZeroWrapLimited(1, n));
            }
        }
        else {
            if (is_positive(vexp)) {
                y = NewZeroWrapLimited(1, n);
                VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
                return VpCheckGetValue(y);
            }
            else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
                return VpCheckGetValue(NewZeroWrapLimited(-1, n));
            }
            else {
                return VpCheckGetValue(NewZeroWrapLimited(1, n));
            }
        }
    }

    int_exp = FIX2LONG(vexp);
    ma = int_exp;
    if (ma <  0) ma = -ma;
    if (ma == 0) ma = 1;

    if (VpIsDef(x)) {
        mp = x->Prec * (VpBaseFig() + 1);
        GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
    }
    else {
        GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
    }
    VpPowerByInt(y, x, int_exp);
    if (!NIL_P(prec) && VpIsDef(y)) {
        VpMidRound(y, VpGetRoundMode(), n);
    }
    return VpCheckGetValue(y);
}
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
static VALUE
BigDecimal_precision(VALUE self)
{
    ssize_t precision;
    BigDecimal_count_precision_and_scale(self, &precision, NULL);
    return SSIZET2NUM(precision);
}
precision_scale → [integer, integer] 按一下以切換來源

傳回長度為 2 的陣列;第一個項目是 BigDecimal#precision 的結果,第二個項目是 BigDecimal#scale 的結果。

請參閱 BigDecimal#precision。請參閱 BigDecimal#scale

static VALUE
BigDecimal_precision_scale(VALUE self)
{
    ssize_t precision, scale;
    BigDecimal_count_precision_and_scale(self, &precision, &scale);
    return rb_assoc_new(SSIZET2NUM(precision), SSIZET2NUM(scale));
}
precs → array 按一下以切換來源

傳回 Array,其中包含兩個 Integer 值,代表與平台相關的內部儲存特性。

此方法已過時,未來將予以移除。請改用 BigDecimal#n_significant_digits 來取得科學記號中的有效位數,以及 BigDecimal#precision 來取得十進位記號中的位數。

static VALUE
BigDecimal_prec(VALUE self)
{
    ENTER(1);
    Real *p;
    VALUE obj;

    rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
                     "BigDecimal#precs is deprecated and will be removed in the future; "
                     "use BigDecimal#precision instead.");

    GUARD_OBJ(p, GetVpValue(self, 1));
    obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
                       SIZET2NUM(p->MaxPrec*VpBaseFig()));
    return obj;
}
quo(value) → bigdecimal 按一下以切換來源
quo(value, digits) → bigdecimal

除以指定的值。

digits

如果指定且小於結果的有效數字,則根據 BigDecimal.mode 指示的捨入模式,將結果捨入到給定的數字。

如果 digits 為 0 或省略,則結果與 / 運算子相同。

請參閱 BigDecimal#/。請參閱 BigDecimal#div

static VALUE
BigDecimal_quo(int argc, VALUE *argv, VALUE self)
{
    VALUE value, digits, result;
    SIGNED_VALUE n = -1;

    argc = rb_scan_args(argc, argv, "11", &value, &digits);
    if (argc > 1) {
        n = check_int_precision(digits);
    }

    if (n > 0) {
        result = BigDecimal_div2(self, value, digits);
    }
    else {
        result = BigDecimal_div(self, value);
    }

    return result;
}
remainder(value) 按一下以切換來源

傳回除以該值的餘數。

x.remainder(y) 表示 x-y*(x/y).truncate

static VALUE
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
{
    VALUE  f;
    Real  *d, *rv = 0;
    f = BigDecimal_divremain(self, r, &d, &rv);
    if (!NIL_P(f)) return f;
    return VpCheckGetValue(rv);
}
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 且為正數,結果的小數部分不會超過該數字位數。

如果指定 n 且為負數,則結果中在小數點左側的數字至少有這麼多個會是 0,且傳回值會是 Integer

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

可使用選用模式引數的值來決定如何執行捨入;請參閱 BigDecimal.mode

static VALUE
BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real   *c, *a;
    int    iLoc = 0;
    VALUE  vLoc;
    VALUE  vRound;
    int    round_to_int = 0;
    size_t mx, pl;

    unsigned short sw = VpGetRoundMode();

    switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
      case 0:
        iLoc = 0;
        round_to_int = 1;
        break;
      case 1:
        if (RB_TYPE_P(vLoc, T_HASH)) {
            sw = check_rounding_mode_option(vLoc);
        }
        else {
            iLoc = NUM2INT(vLoc);
            if (iLoc < 1) round_to_int = 1;
        }
        break;
      case 2:
        iLoc = NUM2INT(vLoc);
        if (RB_TYPE_P(vRound, T_HASH)) {
            sw = check_rounding_mode_option(vRound);
        }
        else {
            sw = check_rounding_mode(vRound);
        }
        break;
      default:
        break;
    }

    pl = VpSetPrecLimit(0);
    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, sw, iLoc);
    if (round_to_int) {
        return BigDecimal_to_i(VpCheckGetValue(c));
    }
    return VpCheckGetValue(c);
}
scale → integer 按一下以切換來源

傳回 self 中小數位數後面的位數。

BigDecimal("0").scale         # => 0
BigDecimal("1").scale         # => 0
BigDecimal("1.1").scale       # => 1
BigDecimal("3.1415").scale    # => 4
BigDecimal("-1e20").precision # => 0
BigDecimal("1e-20").precision # => 20
BigDecimal("Infinity").scale  # => 0
BigDecimal("-Infinity").scale # => 0
BigDecimal("NaN").scale       # => 0
static VALUE
BigDecimal_scale(VALUE self)
{
    ssize_t scale;
    BigDecimal_count_precision_and_scale(self, NULL, &scale);
    return SSIZET2NUM(scale);
}
sign() 按一下以切換來源

傳回該值的符號。

如果 > 0,則傳回正值;如果 < 0,則傳回負值。它對零的行為相同 - 它會傳回正值給正零 (BigDecimal(‘0’)),傳回負值給負零 (BigDecimal(‘-0’))。

傳回的特定值表示 BigDecimal 的類型和符號,如下所示

BigDecimal::SIGN_NaN

值不是數字

BigDecimal::SIGN_POSITIVE_ZERO

值為 +0

BigDecimal::SIGN_NEGATIVE_ZERO

值為 -0

BigDecimal::SIGN_POSITIVE_INFINITE

值為 +Infinity

BigDecimal::SIGN_NEGATIVE_INFINITE

值為 -Infinity

BigDecimal::SIGN_POSITIVE_FINITE

值為正數

BigDecimal::SIGN_NEGATIVE_FINITE

值為負數

static VALUE
BigDecimal_sign(VALUE self)
{ /* sign */
    int s = GetVpValue(self, 1)->sign;
    return INT2FIX(s);
}
split() 按一下以切換來源

BigDecimal 數字拆分成四個部分,並傳回一個值陣列。

第一個值表示 BigDecimal 的符號,為 -1 或 1,如果 BigDecimal 不是數字,則為 0。

第二個值是一個字串,表示 BigDecimal 的有效數字,沒有前導零。

第三個值是作為 Integer 使用的算術運算基礎(目前永遠是 10)。

第四個值是 Integer 指數。

如果 BigDecimal 可以表示為 0.xxxxxx*10**n,則 xxxxxx 是不帶前導零的重要數字字串,而 n 是指數。

根據這些值,您可以將 BigDecimal 轉換為浮點數,如下所示

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

(請注意,to_f 方法提供一種更方便的方式,將 BigDecimal 轉換為 Float。)

static VALUE
BigDecimal_split(VALUE self)
{
    ENTER(5);
    Real *vp;
    VALUE obj,str;
    ssize_t e, s;
    char *psz1;

    GUARD_OBJ(vp, GetVpValue(self, 1));
    str = rb_str_new(0, VpNumOfChars(vp, "E"));
    psz1 = RSTRING_PTR(str);
    VpSzMantissa(vp, psz1, RSTRING_LEN(str));
    s = 1;
    if(psz1[0] == '-') {
        size_t len = strlen(psz1 + 1);

        memmove(psz1, psz1 + 1, len);
        psz1[len] = '\0';
        s = -1;
    }
    if (psz1[0] == 'N') s = 0; /* NaN */
    e = VpExponent10(vp);
    obj = rb_ary_new2(4);
    rb_ary_push(obj, INT2FIX(s));
    rb_ary_push(obj, str);
    rb_str_resize(str, strlen(psz1));
    rb_ary_push(obj, INT2FIX(10));
    rb_ary_push(obj, SSIZET2NUM(e));
    return obj;
}
sqrt(n) 按一下以切換來源

傳回值的平方根。

結果至少有 n 個有效數字。

static VALUE
BigDecimal_sqrt(VALUE self, VALUE nFig)
{
    ENTER(5);
    Real *c, *a;
    size_t mx, n;

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);

    n = check_int_precision(nFig);
    n += VpDblFig() + VpBaseFig();
    if (mx <= n) mx = n;
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpSqrt(c, a);
    return VpCheckGetValue(c);
}
sub(value, digits) → bigdecimal 按一下以切換來源

減去指定的值。

例如:

c = a.sub(b,n)
digits

如果指定且小於結果的有效數字位數,結果會根據 BigDecimal.mode 捨入到該數字位數。

static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = check_int_precision(n);
    if (mx == 0) return BigDecimal_sub(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_sub(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return VpCheckGetValue(cv);
    }
}
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” 的 String。此方法已棄用;請改用 BigDecimal#to_s(“F”)。

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_digits                  # => "3.14"
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 90
def to_digits
  if self.nan? || self.infinite? || self.zero?
    self.to_s
  else
    i       = self.to_i.to_s
    _,f,_,z = self.frac.split
    i + "." + ("0"*(-z)) + f
  end
end
to_f() 按一下以切換來源

傳回一個新的 Float 物件,其值與 BigDecimal 數字近似相同。套用正常的準確度限制和二進制 Float 算術內建錯誤。

static VALUE
BigDecimal_to_f(VALUE self)
{
    ENTER(1);
    Real *p;
    double d;
    SIGNED_VALUE e;
    char *buf;
    volatile VALUE str;

    GUARD_OBJ(p, GetVpValue(self, 1));
    if (VpVtoD(&d, &e, p) != 1)
        return rb_float_new(d);
    if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
        goto overflow;
    if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
        goto underflow;

    str = rb_str_new(0, VpNumOfChars(p, "E"));
    buf = RSTRING_PTR(str);
    VpToString(p, buf, RSTRING_LEN(str), 0, 0);
    errno = 0;
    d = strtod(buf, 0);
    if (errno == ERANGE) {
        if (d == 0.0) goto underflow;
        if (fabs(d) >= HUGE_VAL) goto overflow;
    }
    return rb_float_new(d);

overflow:
    VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
    if (BIGDECIMAL_NEGATIVE_P(p))
        return rb_float_new(VpGetDoubleNegInf());
    else
        return rb_float_new(VpGetDoublePosInf());

underflow:
    VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
    if (BIGDECIMAL_NEGATIVE_P(p))
        return rb_float_new(-0.0);
    else
        return rb_float_new(0.0);
}
to_i() 按一下以切換來源

將值傳回為 Integer

如果 BigDecimal 是無限大或 NaN,則會引發 FloatDomainError

static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    ssize_t e, nf;
    Real *p;

    GUARD_OBJ(p, GetVpValue(self, 1));
    BigDecimal_check_num(p);

    e = VpExponent10(p);
    if (e <= 0) return INT2FIX(0);
    nf = VpBaseFig();
    if (e <= nf) {
        return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
    }
    else {
        VALUE a = BigDecimal_split(self);
        VALUE digits = RARRAY_AREF(a, 1);
        VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
        VALUE ret;
        ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);

        if (BIGDECIMAL_NEGATIVE_P(p)) {
            numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
        }
        if (dpower < 0) {
            ret = rb_funcall(numerator, rb_intern("div"), 1,
                              rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                         INT2FIX(-dpower)));
        }
        else {
            ret = rb_funcall(numerator, '*', 1,
                             rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                        INT2FIX(dpower)));
        }
        if (RB_TYPE_P(ret, T_FLOAT)) {
            rb_raise(rb_eFloatDomainError, "Infinity");
        }
        return ret;
    }
}
別名:to_int
to_int()

將值傳回為 Integer

如果 BigDecimal 是無限大或 NaN,則會引發 FloatDomainError

別名:to_i
to_json(*args) 按一下以切換來源

傳回代表 selfJSON 字串

require 'json/add/bigdecimal'
puts BigDecimal(2).to_json
puts BigDecimal(2.0, 4).to_json
puts BigDecimal(Complex(2, 0)).to_json

輸出

{"json_class":"BigDecimal","b":"27:0.2e1"}
{"json_class":"BigDecimal","b":"36:0.2e1"}
{"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

static VALUE
BigDecimal_to_r(VALUE self)
{
    Real *p;
    ssize_t sign, power, denomi_power;
    VALUE a, digits, numerator;

    p = GetVpValue(self, 1);
    BigDecimal_check_num(p);

    sign = VpGetSign(p);
    power = VpExponent10(p);
    a = BigDecimal_split(self);
    digits = RARRAY_AREF(a, 1);
    denomi_power = power - RSTRING_LEN(digits);
    numerator = rb_funcall(digits, rb_intern("to_i"), 0);

    if (sign < 0) {
        numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
    }
    if (denomi_power < 0) {
        return rb_Rational(numerator,
                           rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                      INT2FIX(-denomi_power)));
    }
    else {
        return rb_Rational1(rb_funcall(numerator, '*', 1,
                                       rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                                  INT2FIX(denomi_power))));
    }
}
to_s(s) 按一下以切換來源

將值轉換為字串。

預設格式類似於 0.xxxxEnn。

選用參數 s 包含整數;或選用的「+」或「 」,後接選用的數字,後接選用的「E」或「F」。

如果 s 的開頭有「+」,則正值會以開頭的「+」傳回。

s 開頭的空格會傳回開頭有空格的正值。

如果 s 包含數字,則會在從「.」開始並向外計算的每組數字後插入空格。

如果 s 以「E」結尾,則會使用工程記號法 (0.xxxxEnn)。

如果 s 以「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'
static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    int   fmt = 0;   /* 0: E format, 1: F format */
    int   fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
    Real  *vp;
    volatile VALUE str;
    char  *psz;
    char   ch;
    size_t nc, mc = 0;
    SIGNED_VALUE m;
    VALUE  f;

    GUARD_OBJ(vp, GetVpValue(self, 1));

    if (rb_scan_args(argc, argv, "01", &f) == 1) {
        if (RB_TYPE_P(f, T_STRING)) {
            psz = StringValueCStr(f);
            if (*psz == ' ') {
                fPlus = 1;
                psz++;
            }
            else if (*psz == '+') {
                fPlus = 2;
                psz++;
            }
            while ((ch = *psz++) != 0) {
                if (ISSPACE(ch)) {
                    continue;
                }
                if (!ISDIGIT(ch)) {
                    if (ch == 'F' || ch == 'f') {
                        fmt = 1; /* F format */
                    }
                    break;
                }
                mc = mc*10 + ch - '0';
            }
        }
        else {
            m = NUM2INT(f);
            if (m <= 0) {
                rb_raise(rb_eArgError, "argument must be positive");
            }
            mc = (size_t)m;
        }
    }
    if (fmt) {
        nc = VpNumOfChars(vp, "F");
    }
    else {
        nc = VpNumOfChars(vp, "E");
    }
    if (mc > 0) {
        nc += (nc + mc - 1) / mc + 1;
    }

    str = rb_usascii_str_new(0, nc);
    psz = RSTRING_PTR(str);

    if (fmt) {
        VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
    }
    else {
        VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
    }
    rb_str_resize(str, strlen(psz));
    return str;
}
truncate(n) 按一下以切換來源

截斷為最接近的整數 (預設),並將結果傳回為 BigDecimal

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

如果指定 n 且為正數,結果的小數部分不會超過該數字位數。

如果指定 n 且為負數,結果的小數點左方至少會有該數字位數為 0。

BigDecimal('3.14159').truncate(3) #=> 3.141
BigDecimal('13345.234').truncate(-2) #=> 13300.0
static VALUE
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
        iLoc = 0;
    }
    else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
    if (argc == 0) {
        return BigDecimal_to_i(VpCheckGetValue(c));
    }
    return VpCheckGetValue(c);
}
zero?() 按一下以切換來源

如果值為零,則傳回 True。

static VALUE
BigDecimal_zero(VALUE self)
{
    Real *a = GetVpValue(self, 1);
    return VpIsZero(a) ? Qtrue : Qfalse;
}