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 <shigeo@tinyforest.gr.jp>。
BigDecimal 在 Ruby 和 2-clause BSD 许可证下发布。有关详细信息,请参阅 LICENSE.txt。
由 mrkn <mrkn@mrkn.jp> 和 ruby-core 成员维护。
由 zzak <zachary@zacharyscott.net>、mathew <meta@pobox.com> 和许多其他贡献者编写文档。
常量
- 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;
}