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
的類型
-
如果
value
是浮點數,精度為 Float::DIG + 1。 -
如果
value
是有理數,精度大於 Float::DIG + 1。 -
如果
value
是 BigDecimal,則精度是value
在內部表示中的精度,這取決於平台。 -
如果
value
是其他物件,則精度由 +BigDecimal(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.0
和 0.0
被視為相同。
另請注意,在數學中,沒有特別的負零或正零概念;真正的數學零沒有符號。
bigdecimal/util¶ ↑
當你需要 bigdecimal/util
時,to_d
方法將會在 BigDecimal
和原生 Integer
、Float
、Rational
和 String
類別中提供。
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'
版權所有 © 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 函式庫的版本
公共類別方法
用於提供封送支援的內部方法。請參閱 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); }
傳回 Float
物件允許擁有的數字數量;結果取決於系統
BigDecimal.double_fig # => 16
static inline VALUE BigDecimal_double_fig(VALUE self) { return INT2FIX(VpDblFig()); }
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); }
請參閱 as_json
。
# File ext/json/lib/json/add/bigdecimal.rb, line 13 def self.json_create(object) BigDecimal._load object['b'] end
將新建立的 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; }
傳回表示例外處理和捨入的模式設定的整數。
這些模式控制例外處理
-
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; }
執行提供的區塊,但保留例外模式
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; }
執行提供的區塊,但保留精確度限制
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; }
執行提供的區塊,但保留四捨五入模式
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; }
公開實例方法
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 值
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 總和
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); }
傳回 self
+BigDecimal(5) # => 0.5e1 +BigDecimal(-5) # => -0.5e1
static VALUE BigDecimal_uplus(VALUE self) { return self; }
傳回 self
和 value
的 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 負數
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); }
除以指定的值。
結果精度會是較大運算元的精度,但其最小值是 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
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
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'); }
比較運算子。如果 a == b,則 a <=> b 為 0;如果 a > b,則為 1;如果 a < b,則為 -1。
static VALUE BigDecimal_comp(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '*'); }
測試值相等性;如果值相等,則傳回 true。
對於 BigDecimal
,== 和 === 運算子以及 eql? 方法具有相同的實作。
可以強制轉換值以執行比較
BigDecimal('1.0') == 1.0 #=> true
static VALUE BigDecimal_eq(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '='); }
測試值相等性;如果值相等,則傳回 true。
對於 BigDecimal
,== 和 === 運算子以及 eql? 方法具有相同的實作。
可以強制轉換值以執行比較
BigDecimal('1.0') == 1.0 #=> true
如果 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
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'); }
傳回表示 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; }
傳回 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); }
傳回 self
和 value
的 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); } }
方法 BigDecimal#as_json
和 BigDecimal.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
傳回小於或等於該值的最小整數,作為 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); }
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; }
除以指定的值。
- 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); }
依指定值除,並傳回商數和餘數為 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")); }
測試值相等性;如果值相等,則傳回 true。
對於 BigDecimal
,== 和 === 運算子以及 eql? 方法具有相同的實作。
可以強制轉換值以執行比較
BigDecimal('1.0') == 1.0 #=> true
傳回 BigDecimal
數字的指數,為 Integer
。
如果數字可以表示為 0.xxxxxx*10**n,其中 xxxxxx 是沒有前導零的數字字串,則 n 為指數。
static VALUE BigDecimal_exponent(VALUE self) { ssize_t e = VpExponent10(GetVpValue(self, 1)); return SSIZET2NUM(e); }
如果值是有限的(不是 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; }
傳回數字的整數部分,為 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); }
傳回小於或等於該值的最大的整數,為 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); }
傳回數字的小數部分,為 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); }
傳回 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); }
根據值是有限、-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; }
傳回 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; }
傳回 self
和 value
的 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); } }
傳回 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); }
如果值不是數字,則傳回 True。
static VALUE BigDecimal_IsNaN(VALUE self) { Real *p = GetVpValue(self, 1); if (VpIsNaN(p)) return Qtrue; return Qfalse; }
如果值是非零值,則傳回 self,否則傳回 nil。
static VALUE BigDecimal_nonzero(VALUE self) { Real *a = GetVpValue(self, 1); return VpIsZero(a) ? Qnil : self; }
傳回提升至 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); }
傳回 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); }
傳回長度為 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)); }
傳回 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; }
除以指定的值。
- 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; }
傳回除以該值的餘數。
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); }
捨入到最接近的整數(預設),如果指定 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); }
傳回 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); }
傳回該值的符號。
如果 > 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); }
將 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; }
傳回值的平方根。
結果至少有 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); }
減去指定的值。
例如:
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); } }
傳回 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
將 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
傳回一個新的 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); }
將值傳回為 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; } }
傳回代表 self
的 JSON
字串
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
將 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)))); } }
將值轉換為字串。
預設格式類似於 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; }
截斷為最接近的整數 (預設),並將結果傳回為 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); }
如果值為零,則傳回 True。
static VALUE BigDecimal_zero(VALUE self) { Real *a = GetVpValue(self, 1); return VpIsZero(a) ? Qtrue : Qfalse; }