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
是大十进制数,则精度为内部表示中的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
朝 +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); }
返回 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; }
返回除以 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 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; }