class BigDecimal
BigDecimal
提供任意精度的浮点十进制算术。
简介¶ ↑
Ruby 提供对任意精度整数算术的内置支持。
例如
42**13 #=> 1265437718438866624512
BigDecimal
为非常大或非常精确的浮点数提供类似的支持。
十进制算术对于一般计算也很有用,因为它提供了人们期望的正确答案——而普通的二进制浮点算术由于十进制和二进制之间的转换,常常会引入细微的错误。
例如,尝试
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,则精度为 Float::DIG + 1。 -
如果
value
是 Rational,则精度大于 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¶ ↑
当您 require 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 Shigeo Kobayashi <[email protected]>。
BigDecimal
在 Ruby 和 2-clause 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
BigDecimal
中的无穷大] 值。- NAN
BigDecimal
中的非数字]’ 值。- 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()); }
返回从 string
松散转换的 BigDecimal
。
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_* 一起使用
请参阅 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; }
公共实例方法
乘以指定的值。
结果精度将是每个精度之和的精度。
请参阅 BigDecimal#mult
。
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 并且为负数,则结果中小数点左侧至少有那么多位数字为 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。
== 和 === 运算符以及 eql? 方法对于 BigDecimal
具有相同的实现。
可以强制转换值以执行比较
BigDecimal('1.0') == 1.0 #=> true
以 Integer
的形式返回 BigDecimal
数字的指数。
如果可以将该数字表示为 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)); }
返回一个由两个 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
可选的 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); } }
返回 self。
require 'bigdecimal/util' d = BigDecimal("3.14") d.to_d # => 0.314e1
# File bigdecimal-3.1.8/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-3.1.8/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 并且为负数,则结果中小数点左侧至少有那么多位数字为 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; }