BigDecimal
Parent:Numeric
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.new("0")
10_000.times do
sum = sum + BigDecimal.new("0.0001")
end
print sum #=> 0.1E1
同理:
(BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true
(1.2 - 1.0) == 0.2 #=> false
精确小数运算的特点
由于BigDecimal比普通二进制浮点算法更精确,因此它需要一些特殊值。
无穷
BigDecimal有时需要返回无穷大,例如,如果您将值除以零。
BigDecimal.new("1.0") / BigDecimal.new("0.0") #=> Infinity
BigDecimal.new("-1.0") / BigDecimal.new("0.0") #=> -Infinity
您可以使用字符串将无限数字表示为BigDecimal 'Infinity'
,'+Infinity'
并且'-Infinity'
(区分大小写)
不是数字
当计算结果为未定义的值时,返回特殊值NaN
(对于'不是数字')。
例:
BigDecimal.new("0.0") / BigDecimal.new("0.0") #=> NaN
您也可以创建未定义的值。
NaN永远不会被视为与其他任何价值相同,即使NaN本身也是如此:
n = BigDecimal.new('NaN')
n == 0.0 #=> false
n == n #=> false
正面和负面的零
如果计算结果的值太小而不能在当前指定的精度范围内表示为BigDecimal,则必须返回零。
如果太小而不能表示的值是负数,则返回负零的BigDecimal值。
BigDecimal.new("1.0") / BigDecimal.new("-Infinity") #=> -0.0
如果该值为正值,则返回正值零。
BigDecimal.new("1.0") / BigDecimal.new("Infinity") #=> 0.0
(有关如何指定精度限制的信息,请参阅:: mode。)
请注意,为了进行比较-0.0
,0.0
被认为是相同的。
还要注意,在数学中,没有特别的负或正零概念; 真正的数学零点没有标志。
执照
Shigeo Kobayashi版权所有(C)2002 shigeo@tinyforest.gr.jp。
BigDecimal在Ruby和2子句BSD许可下发布。详情请参阅LICENSE.txt。
由mrkn mrkn@mrkn.jp和ruby-core成员维护。
由zzak zachary @ zacharyscott.net,mathew meta@pobox.com和其他许多贡献者记录。
BigDecimal扩展了本地Numeric类以提供to_digits和to_d方法。
当您在应用程序中需要BigDecimal时,此方法将在BigDecimal对象上可用。
常量
BASE
内部计算中使用的基准值。在32位系统上,BASE为10000,表示计算是以4位数组的方式完成的。(如果它更大,BASE ** 2将不适合32位,所以你不能保证两个组可以总是相乘而不会溢出。)
EXCEPTION_ALL
确定溢出,下溢或零分是否导致引发异常。请参阅:: mode。
EXCEPTION_INFINITY
确定计算结果无穷时发生的情况。请参阅:: mode。
EXCEPTION_NaN
确定计算结果不是数字(NaN)时发生的情况。请参阅:: mode。
EXCEPTION_OVERFLOW
确定计算结果是溢出时的结果(结果太大而无法表示)。请参阅:: mode。
EXCEPTION_UNDERFLOW
确定计算结果是下溢时发生的情况(结果太小而无法表示)。请参阅:: mode。
EXCEPTION_ZERODIVIDE
确定执行零除时发生的情况。请参阅:: mode。
INFINITY
正无限价值。
NAN
'Not a Number' value.
ROUND_CEILING
Round towards +Infinity. See ::mode.
ROUND_DOWN
指示值应该朝零调整。请参阅:: mode。
ROUND_FLOOR
Round towards -Infinity. See ::mode.
ROUND_HALF_DOWN
表示数字>= 6应该四舍五入,其他四舍五入。请参阅 ::mode。
ROUND_HALF_EVEN
围绕着偶像邻居。请参阅:: mode。
ROUND_HALF_UP
表示数字>= 5应该四舍五入,其他四舍五入。请参阅 ::mode。
ROUND_MODE
确定结果必须四舍五入以适应适当的有效数字位数时会发生什么情况。请参阅 ::mode。
ROUND_UP
指示值应该从零圆整。请参阅 ::mode。
SIGN_NEGATIVE_FINITE
表示一个值是负的和有限的。请参阅#sign。
SIGN_NEGATIVE_INFINITE
表示一个值是负值而且是无限的。请参阅#sign。
SIGN_NEGATIVE_ZERO
指示值为-0。请参阅#sign。
SIGN_NaN
表示一个值不是一个数字。请参阅#sign。
SIGN_POSITIVE_FINITE
表示一个值是正数和有限的。请参阅#sign。
SIGN_POSITIVE_INFINITE
表示一个值是正数和无穷大。请参阅#sign。
SIGN_POSITIVE_ZERO
表示一个值是+0。请参阅#sign。
公共类方法
_load(p1) Show source
用于提供编组支持的内部方法。请参阅Marshal模块。
static VALUE
BigDecimal_load(VALUE self, VALUE str)
{
ENTER(2);
Real *pv;
unsigned char *pch;
unsigned char ch;
unsigned long m=0;
SafeStringValue(str);
pch = (unsigned char *)RSTRING_PTR(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));
m /= VpBaseFig();
if (m && pv->MaxPrec > m) {
pv->MaxPrec = m+1;
}
return ToValue(pv);
}
double_fig显示源代码
::double_fig类方法返回浮点数允许拥有的位数。结果取决于正在使用的CPU和操作系统。
static VALUE
BigDecimal_double_fig(VALUE self)
{
return INT2FIX(VpDblFig());
}
json_create(object) Show source
导入JSON Marshalled对象。
用于JSON编组支持的方法。
# File ext/json/lib/json/add/bigdecimal.rb, line 11
def self.json_create(object)
BigDecimal._load object['b']
end
limit(digits) Show source
将新创建的BigDecimal数字中的有效位数限制为指定的值。根据需要执行舍入,如:: mode所指定。
默认值0表示没有上限。
此方法指定的限制优先于指定给实例方法(如ceil,floor,truncate或round)的任何限制的优先级。
static VALUE
BigDecimal_limit(int argc, VALUE *argv, VALUE self)
{
VALUE nFig;
VALUE nCur = INT2NUM(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;
}
mode(mode, value) Show source
控制算术例外和舍入的处理。如果没有提供值,则返回当前值。
模式参数的六个值控制算术例外的处理:
BigDecimal::EXCEPTION_NaN BigDecimal::EXCEPTION_INFINITY BigDecimal::EXCEPTION_UNDERFLOW BigDecimal::EXCEPTION_OVERFLOW BigDecimal::EXCEPTION_ZERODIVIDE BigDecimal::EXCEPTION_ALL
对于上面的每个模式参数,如果该值设置为false,则计算在相应类型的算术异常之后继续。当计算继续时,结果如下:
EXCEPTION_NaN
NaN
EXCEPTION_INFINITY
+Infinity or -Infinity
EXCEPTION_UNDERFLOW
0
EXCEPTION_OVERFLOW
+Infinity or -Infinity
EXCEPTION_ZERODIVIDE
+Infinity or -Infinity
mode参数的一个值控制数值的舍入:BigDecimal :: ROUND_MODE。它可以采取的值是:
ROUND_UP, :up
round away from zero
ROUND_DOWN, :down, :truncate
round towards zero (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
向负无穷(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;
}
new(initial, digits) Show source
创建一个新的BigDecimal对象。
initial
初始值,作为Integer,Float,Rational,BigDecimal或String。
如果它是一个字符串,则会忽略空格,并且无法识别的字符将终止该值。
digits
有效数字的数量,作为整数。如果省略或0,则有效位数由初始值确定。
计算中使用的有效数字的实际数量通常大于指定的数字。
例外
TypeError
如果该initial
类型既不是Integer,Float,Rational,也不是BigDecimal,则会引发此异常。
TypeError
如果digits
不是整数,则引发此异常。
ArgumentError
如果initial
是Float,并且digits
大于Float :: DIG + 1,则引发此异常。
ArgumentError
如果initial
是Float或Rational,并且该digits
值被省略,则引发此异常。
static VALUE
BigDecimal_initialize(int argc, VALUE *argv, VALUE self)
{
ENTER(1);
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
Real *x;
GUARD_OBJ(x, BigDecimal_new(argc, argv));
if (ToValue(x)) {
pv = VpCopy(pv, x);
}
else {
VpFree(pv);
pv = x;
}
DATA_PTR(self) = pv;
pv->obj = self;
return self;
}
save_exception_mode { ... } Show source
执行提供的块,但保留异常模式
BigDecimal.save_exception_mode do
BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
BigDecimal.new(BigDecimal('Infinity'))
BigDecimal.new(BigDecimal('-Infinity'))
BigDecimal(BigDecimal.new('NaN'))
end
For use with the BigDecimal::EXCEPTION_*
请参阅:: 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;
}
save_limit { ... } Show source
执行提供的块,但保留精度限制
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;
}
save_rounding_mode { ... } Show source
执行提供的块,但保留舍入模式
BigDecimal.save_rounding_mode do
BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
puts BigDecimal.mode(BigDecimal::ROUND_MODE)
end
用于BigDecimal :: ROUND_ *
请参阅:: 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;
}
ver() Show source
返回BigDecimal版本号。
static VALUE
BigDecimal_version(VALUE self)
{
/*
* 1.0.0: Ruby 1.8.0
* 1.0.1: Ruby 1.8.1
* 1.1.0: Ruby 1.9.3
*/
return rb_str_new2("1.1.0");
}
公共实例方法
a%b显示来源
返回除以b得到的模量。
请参阅#divmod。
static VALUE
BigDecimal_mod(VALUE self, VALUE r)
mult(value, digits) Show source
乘以指定的值。
例如
c = a.mult(b,n)
c = a * b
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
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, DBL_DIG+1, 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, VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
VpMult(c, a, b);
return ToValue(c);
}
a ** n→bigdecimal显示源
返回n的幂的值。
请参阅#power。
static VALUE
BigDecimal_power_op(VALUE self, VALUE exp)
{
return BigDecimal_power(1, &exp, self);
}
add(value, digits) 显示源
添加指定的值。
例如
c = a.add(b,n)
c = a + b
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
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, DBL_DIG+1, 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,VpCreateRbObject(VpBaseFig() + 1, "0"));
VpAddSub(c, a, b, 1);
}
else {
GUARD_OBJ(c, VpCreateRbObject(mx * (VpBaseFig() + 1), "0"));
if(!mx) {
VpSetInf(c, VpGetSign(a));
}
else {
VpAddSub(c, a, b, 1);
}
}
return ToValue(c);
}
+ big_decimal→big_decimal显示源文件
返回自身
+BigDecimal('5') #=> 0.5e1
static VALUE
BigDecimal_uplus(VALUE self)
{
return self;
}
a - b→bigdecimal显示源代码
减去指定的值。
e.g.
c = a - b
结果值的精度取决于类型b
。
如果b
是浮点数,结果的精度是Float :: DIG + 1。
如果b是BigDecimal,则结果的精度是b从平台内部表示的精度。 所以,它的返回值取决于平台。
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, DBL_DIG+1, 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,VpCreateRbObject(VpBaseFig() + 1, "0"));
VpAddSub(c, a, b, -1);
}
else {
GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
if (!mx) {
VpSetInf(c,VpGetSign(a));
}
else {
VpAddSub(c, a, b, -1);
}
}
return ToValue(c);
}
-big_decimal→big_decimal显示源
返回自身的否定模式。
-BigDecimal('5') #=> -0.5e1
static VALUE
BigDecimal_neg(VALUE self)
{
ENTER(5);
Real *c, *a;
GUARD_OBJ(a, GetVpValue(self, 1));
GUARD_OBJ(c, VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
VpAsgn(c, a, -1);
return ToValue(c);
}
div(value, digits)显示源
quo(value)
除以指定的值。
e.g.
c = a.div(b,n)
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
如果数字为0,则结果与/运算符相同。如果不是,则结果是一个BigDecimal整数,与Numeric#div类似。
提供别名,因为div(value, 0)
与计算商数相同; 请参阅#divmod。
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(&c, &res, &div, self, r);
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], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
}
return ToValue(c);
}
a <b显示源
如果a小于b,则返回true。
值可能会被强制执行比较(请参阅==,#coerce)。
static VALUE
BigDecimal_lt(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '<');
}
a <= b显示源
如果a小于或等于b,则返回true。
值可能会被强制执行比较(请参阅==,#coerce)。
static VALUE
BigDecimal_le(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, 'L');
}
<=>(p1)显示源文件
比较运算符。a <=>如果a == b,则b为0,如果a> b则为1,如果a <b则为-1。
static VALUE
BigDecimal_comp(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '*');
}
==(p1)显示源文件
等价测试; 如果值相等,则返回true。
==和===运算符和eql?方法对于BigDecimal具有相同的实现。
值可能会被强制执行比较:
BigDecimal.new('1.0') == 1.0 #=> true
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '=');
}
===(p1)显示源文件
等价测试; 如果值相等,则返回true。
==和===运算符和eql?方法对于BigDecimal具有相同的实现。
值可能会被强制执行比较:
BigDecimal.new('1.0') == 1.0 #=> true
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '=');
}
a> b显示来源
如果a大于b,则返回true。
值可能会被强制执行比较(请参阅==,#coerce)。
static VALUE
BigDecimal_gt(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '>');
}
a> = b显示来源
如果a大于或等于b,则返回true。
值可能会被强制执行比较(请参阅==,#coerce)
static VALUE
BigDecimal_ge(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, 'G');
}
_dump显示源文件
用于提供编组支持的方法。
inf = BigDecimal.new('Infinity')
#=> Infinity
BigDecimal._load(inf._dump)
#=> Infinity
请参阅Marshal模块。
static VALUE
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
Real *vp;
char *psz;
VALUE dummy;
volatile VALUE dump;
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);
sprintf(psz, "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
VpToString(vp, psz+strlen(psz), 0, 0);
rb_str_resize(dump, strlen(psz));
return dump;
}
abs→big_decimal显示源代码
以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, VpCreateRbObject(mx, "0"));
VpAsgn(c, a, 1);
VpChangeSign(c, 1);
return ToValue(c);
}
add(value, digits) Show source
+
添加指定的值。
e.g.
c = a.add(b,n)
c = a + b
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
ENTER(2);
Real *cv;
SIGNED_VALUE mx = GetPositiveInt(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 ToValue(cv);
}
}
as_json(*) Show source
将对象编组为JSON。
用于JSON编组支持的方法。
# File ext/json/lib/json/add/bigdecimal.rb, line 18
def as_json(*)
{
JSON.create_id => self.class.name,
'b' => _dump,
}
end
ceil(n) Show source
作为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, VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
if (argc == 0) {
return BigDecimal_to_i(ToValue(c));
}
return ToValue(c);
}
coerce(p1) Show source
强制方法为Ruby类型强制提供支持。它没有默认启用。
这意味着像+ * /或 - 这样的二进制操作通常可以在BigDecimal和另一个类型的对象上执行,如果其他对象可以强制为BigDecimal值。
例如
a = BigDecimal.new("1.0")
b = a / 2.0 #=> 0.5
请注意,将字符串强制转换为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, DBL_DIG+1, 1));
obj = rb_assoc_new(ToValue(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;
}
div(p1,p2 = v2)显示来源
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);
}
divmod(值)显示源
除以指定的值,并将商和模数作为BigDecimal数字返回。商被取整为负无穷。
例如:
require 'bigdecimal'
a = BigDecimal.new("42")
b = BigDecimal.new("9")
q, m = a.divmod(b)
c = q * b + m
a == c #=> true
商q是(a / b).floor,模数是必须加到q * b才能得到的量。
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(ToValue(div), ToValue(mod));
}
return DoSomeOne(self,r,rb_intern("divmod"));
}
eql?(p1) Show source
等价测试; 如果值相等,则返回true。
==和===运算符和eql?方法对于BigDecimal具有相同的实现。
值可能会被强制执行比较:
BigDecimal.new('1.0') == 1.0 #=> true
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
return BigDecimalCmp(self, r, '=');
}
exponent() Show source
以整数形式返回BigDecimal数的指数。
如果数字可以表示为0.xxxxxx * 10 ** n其中xxxxxx是一串没有前导零的数字,则n是指数。
static VALUE
BigDecimal_exponent(VALUE self)
{
ssize_t e = VpExponent10(GetVpValue(self, 1));
return INT2NUM(e);
}
finite?() Show source
如果值是有限的(不是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;
}
fix() Show source
返回数字的整数部分,作为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, VpCreateRbObject(mx, "0"));
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
return ToValue(c);
}
floor(n) Show source
作为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, VpCreateRbObject(mx, "0"));
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(ToValue(c));
}
return ToValue(c);
}
frac() Show source
作为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, VpCreateRbObject(mx, "0"));
VpFrac(c, a);
return ToValue(c);
}
hash Show source
为此BigDecimal创建一个散列。
具有等号,小数部分和指数的两个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(BDIGIT)*p->Prec);
hash += p->exponent;
}
return INT2FIX(hash);
}
infinite?() Show source
返回nil,-1或+1,取决于值是有限的,-Infinity还是+ Infinity。
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;
}
inspect() Show source
将有关该值的调试信息作为尖括号中逗号分隔值的字符串返回,并带有前导#:
BigDecimal.new("1234.5678").inspect
#=> "0.12345678e4"
第一部分是地址,第二部分是作为字符串的值,最后一部分ss(mm)分别是当前有效位数和最大有效位数。
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), 0, 0);
rb_str_resize(str, strlen(RSTRING_PTR(str)));
return str;
}
modulo(b) Show source
返回除以b得到的模量。
请参阅#divmod。
static VALUE
BigDecimal_mod(VALUE self, VALUE r)
mult(value, digits) Show source
乘以指定的值。
e.g.
c = a.mult(b,n)
c = a * b
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
ENTER(2);
Real *cv;
SIGNED_VALUE mx = GetPositiveInt(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 ToValue(cv);
}
}
nan?() Show source
如果值不是数字,则返回True。
static VALUE
BigDecimal_IsNaN(VALUE self)
{
Real *p = GetVpValue(self, 1);
if (VpIsNaN(p)) return Qtrue;
return Qfalse;
}
nonzero?() Show source
如果值为非零,则返回自身,否则为零。
static VALUE
BigDecimal_nonzero(VALUE self)
{
Real *a = GetVpValue(self, 1);
return VpIsZero(a) ? Qnil : self;
}
power(n) Show source
power(n, prec)
返回n的幂的值。
请注意,n必须是整数。
也可以作为操作员**。
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 = VpCreateRbObject(n, "0#");
RB_GC_GUARD(y->obj);
VpSetNaN(y);
return ToValue(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;
}
exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 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);
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;
}
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 = VpCreateRbObject(n, "#0");
RB_GC_GUARD(y->obj);
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);
}
return ToValue(y);
}
else if (is_zero(vexp)) {
return ToValue(VpCreateRbObject(n, "1"));
}
else {
return ToValue(VpCreateRbObject(n, "0"));
}
}
if (is_zero(vexp)) {
return ToValue(VpCreateRbObject(n, "1"));
}
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 ToValue(VpCreateRbObject(n, "0"));
}
else {
/* (-Infinity) ** (-odd_integer) -> -0 */
return ToValue(VpCreateRbObject(n, "-0"));
}
}
else {
/* (-Infinity) ** (-non_integer) -> -0 */
return ToValue(VpCreateRbObject(n, "-0"));
}
}
else {
return ToValue(VpCreateRbObject(n, "0"));
}
}
else {
y = VpCreateRbObject(n, "0#");
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 ToValue(y);
}
}
if (exp != NULL) {
return rmpd_power_by_big_decimal(x, exp, n);
}
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
VALUE abs_value = BigDecimal_abs(self);
if (is_one(abs_value)) {
return ToValue(VpCreateRbObject(n, "1"));
}
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
if (is_negative(vexp)) {
y = VpCreateRbObject(n, "0#");
if (is_even(vexp)) {
VpSetInf(y, VpGetSign(x));
}
else {
VpSetInf(y, -VpGetSign(x));
}
return ToValue(y);
}
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
return ToValue(VpCreateRbObject(n, "-0"));
}
else {
return ToValue(VpCreateRbObject(n, "0"));
}
}
else {
if (is_positive(vexp)) {
y = VpCreateRbObject(n, "0#");
if (is_even(vexp)) {
VpSetInf(y, VpGetSign(x));
}
else {
VpSetInf(y, -VpGetSign(x));
}
return ToValue(y);
}
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
return ToValue(VpCreateRbObject(n, "-0"));
}
else {
return ToValue(VpCreateRbObject(n, "0"));
}
}
}
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, VpCreateRbObject(mp * (ma + 1), "0"));
}
else {
GUARD_OBJ(y, VpCreateRbObject(1, "0"));
}
VpPower(y, x, int_exp);
if (!NIL_P(prec) && VpIsDef(y)) {
VpMidRound(y, VpGetRoundMode(), n);
}
return ToValue(y);
}
precs → array Show source
返回两个整数值的数组。
第一个值是BigDecimal中当前有效数字的数量。第二个值是BigDecimal的最大有效位数。
BigDecimal('5').precs #=> [9, 18]
static VALUE
BigDecimal_prec(VALUE self)
{
ENTER(1);
Real *p;
VALUE obj;
GUARD_OBJ(p, GetVpValue(self, 1));
obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
INT2NUM(p->MaxPrec*VpBaseFig()));
return obj;
}
quo(value) Show source
除以指定的值。
e.g.
c = a.div(b,n)
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
如果数字为0,则结果与/运算符相同。如果不是,则结果是一个BigDecimal整数,与Numeric#div类似。
提供别名,因为div(value, 0)
与计算商数相同; 请参阅#divmod。
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(&c, &res, &div, self, r);
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], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
}
return ToValue(c);
}
remainder(value) Show source
返回除以值所得的余数。
x.remainder(y) means 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 ToValue(rv);
}
round(n, mode) Show source
舍入为最接近的整数(默认值),将结果作为BigDecimal返回。
BigDecimal('3.14159').round #=> 3
BigDecimal('8.7').round #=> 9
BigDecimal('-9.9').round #=> -10
如果n被指定并且是正值,那么结果的小数部分不会超过那么多位数。
如果指定了n并且为负值,则结果中至少小数点左边的许多数字将为0。
BigDecimal('3.14159').round(3) #=> 3.142
BigDecimal('13345.234').round(-2) #=> 13300.0
可选模式参数的值可用于确定如何执行舍入; 请参阅:: mode。
static VALUE
BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
Real *c, *a;
int iLoc = 0;
VALUE vLoc;
VALUE vRound;
size_t mx, pl;
unsigned short sw = VpGetRoundMode();
switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
case 0:
iLoc = 0;
break;
case 1:
if (RB_TYPE_P(vLoc, T_HASH)) {
sw = check_rounding_mode_option(vLoc);
}
else {
iLoc = NUM2INT(vLoc);
}
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, VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c, a, sw, iLoc);
if (argc == 0) {
return BigDecimal_to_i(ToValue(c));
}
return ToValue(c);
}
sign() Show source
返回值的符号。
如果> 0,则返回正值;如果<0,则返回负值,如果== 0则返回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);
}
split() Show source
将BigDecimal数字拆分为四部分,作为值数组返回。
第一个值表示BigDecimal的符号,并且是-1或1,如果BigDecimal不是数字,则为0。
第二个值是一个表示BigDecimal的有效数字的字符串,没有前导零。
第三个值是用于算术的基数(当前总是10)作为整数。
第四个值是一个整数指数。
如果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转换为浮点的更方便的方式提供。)
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);
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, INT2NUM(e));
return obj;
}
sqrt(n) Show source
返回值的平方根。
结果至少有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 = GetPositiveInt(nFig) + VpDblFig() + BASE_FIG;
if (mx <= n) mx = n;
GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
VpSqrt(c, a);
return ToValue(c);
}
sub(value, digits) → bigdecimal Show source
减去指定的值。
e.g.
c = a.sub(b,n)
digits
如果指定并且小于结果的有效位数,则根据::模式将结果舍入到该位数。
static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{
ENTER(2);
Real *cv;
SIGNED_VALUE mx = GetPositiveInt(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 ToValue(cv);
}
}
to_d → bigdecimal Show source
返回自身。
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 96
def to_d
self
end
to_digits → string Show source
将BigDecimal转换为形式为“nnnnnn.mmm”的字符串。此方法已弃用; 改为使用#to_s(“F”)。
require 'bigdecimal'
require 'bigdecimal/util'
d = BigDecimal.new("3.14")
d.to_digits
# => "3.14"
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 82
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
to_f() Show source
返回一个新的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, 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);
}
to_i() Show source
以整数形式返回值。
如果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) * (BDIGIT_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;
}
}
to_int() Show source
以整数形式返回值。
如果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) * (BDIGIT_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;
}
}
to_json(*) Show source
返回JSON值
# File ext/json/lib/json/add/bigdecimal.rb, line 26
def to_json(*)
as_json.to_json
end
to_r() Show source
将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))));
}
}
to_s(s) Show source
将该值转换为字符串。
默认格式看起来像0.xxxxEnn。
可选参数s由一个整数组成; 或可选的'+'或'',后跟可选的数字,然后是可选的'E'或'F'。
如果在s的开头有一个'+',则正值将返回一个前导'+'。
s开始处的空间以正向空间返回正值。
如果s包含一个数字,那么在每个这样的小数位组之后插入一个空格。
如果s以'E'结尾,则使用工程符号(0.xxxxEnn)。
如果s以'F'结尾,则使用常规浮点符号。
例子:
BigDecimal.new('-123.45678901234567890').to_s('5F')
#=> '-123.45678 90123 45678 9'
BigDecimal.new('123.45678901234567890').to_s('+8F')
#=> '+123.45678901 23456789'
BigDecimal.new('123.45678901234567890').to_s(' F')
#=> ' 123.4567890123456789'
static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
int fmt = 0; /* 0:E format */
int fPlus = 0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
Real *vp;
volatile VALUE str;
char *psz;
char ch;
size_t nc, mc = 0;
VALUE f;
GUARD_OBJ(vp, GetVpValue(self, 1));
if (rb_scan_args(argc, argv, "01", &f) == 1) {
if (RB_TYPE_P(f, T_STRING)) {
SafeStringValue(f);
psz = RSTRING_PTR(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 {
mc = (size_t)GetPositiveInt(f);
}
}
if (fmt) {
nc = VpNumOfChars(vp, "F");
}
else {
nc = VpNumOfChars(vp, "E");
}
if (mc > 0) {
nc += (nc + mc - 1) / mc + 1;
}
str = rb_str_new(0, nc);
psz = RSTRING_PTR(str);
if (fmt) {
VpToFString(vp, psz, mc, fPlus);
}
else {
VpToString (vp, psz, mc, fPlus);
}
rb_str_resize(str, strlen(psz));
return str;
}
truncate(n) Show source
截断为最接近的整数(默认情况下),将结果作为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, VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl);
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
if (argc == 0) {
return BigDecimal_to_i(ToValue(c));
}
return ToValue(c);
}
zero?() Show source
如果值为零,则返回True。
static VALUE
BigDecimal_zero(VALUE self)
{
Real *a = GetVpValue(self, 1);
return VpIsZero(a) ? Qtrue : Qfalse;
}
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com