类 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
的包含两个元素的哈希表。 -
#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
向 +Infinity 四舍五入。请参阅
BigDecimal.mode
。- ROUND_DOWN
表示应将值四舍五入为零。请参阅
BigDecimal.mode
。- ROUND_FLOOR
向 -Infinity 四舍五入。请参阅
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); }
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); }
将新创建的 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
临时更改舍入模式,然后自动恢复。
NaNs
模式 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_*
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_*
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。
== 和 === 运算符以及 eql? 方法对 BigDecimal
具有相同的实现。
值可能会被强制转换以执行比较
BigDecimal('1.0') == 1.0 #=> true
static VALUE BigDecimal_eq(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '='); }
测试值相等性;如果值相等,则返回 true。
== 和 === 运算符以及 eql? 方法对 BigDecimal
具有相同的实现。
值可能会被强制转换以执行比较
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
的形式。
BigDecimal('3.14159').ceil #=> 4 BigDecimal('-9.1').ceil #=> -9
如果指定了 n 且为正数,则结果的小数部分最多只有那么多位数字。
如果指定了 n 且为负数,则结果中至少有那么多位数字位于小数点左侧。
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。
== 和 === 运算符以及 eql? 方法对 BigDecimal
具有相同的实现。
值可能会被强制转换以执行比较
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 且为负数,则结果中至少有那么多位数字位于小数点左侧。
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)); }
返回一个包含两个 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; }
返回除以 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); }
舍入到最接近的整数(默认),如果指定了 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
可选的 mode 参数的值可用于确定如何执行舍入;参见 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
的有效数字,没有前导零。
第三个值是用于算术运算的基数(目前始终为 10),作为 Integer
。
第四个值是 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); } }
返回自身。
require 'bigdecimal/util' d = BigDecimal("3.14") d.to_d # => 0.314e1
# File 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 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; } }
将一个 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 且为负数,则结果中至少有那么多位数字位于小数点左侧。
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; }