Class: BigDecimal

Inherits:
Numeric
  • Object
show all
Defined in:
lib/bigdecimal/util.rb,
bigdecimal.c

Overview

BigDecimal provides arbitrary-precision floating point decimal arithmetic.

Copyright © 2002 by Shigeo Kobayashi <[email protected]>. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the README file of the BigDecimal distribution.

Documented by mathew <[email protected]>.

Introduction

Ruby provides built-in support for arbitrary precision integer arithmetic. For example:

42**13 -> 1265437718438866624512

BigDecimal provides similar support for very large or very accurate floating point numbers.

Decimal arithmetic is also useful for general calculation, because it provides the correct answers people expect–whereas normal binary floating point arithmetic often introduces subtle errors because of the conversion between base 10 and base 2. For example, try:

sum = 0
for i in (1..10000)
  sum = sum + 0.0001
end
print sum

and contrast with the output from:

require 'bigdecimal'

sum = BigDecimal.new("0")
for i in (1..10000)
  sum = sum + BigDecimal.new("0.0001")
end
print sum

Similarly:

(BigDecimal.new(“1.2”) - BigDecimal(“1.0”)) == BigDecimal(“0.2”) -> true

(1.2 - 1.0) == 0.2 -> false

Special features of accurate decimal arithmetic

Because BigDecimal is more accurate than normal binary floating point arithmetic, it requires some special values.

Infinity

BigDecimal sometimes needs to return infinity, for example if you divide a value by zero.

BigDecimal.new(“1.0”) / BigDecimal.new(“0.0”) -> infinity

BigDecimal.new(“-1.0”) / BigDecimal.new(“0.0”) -> -infinity

You can represent infinite numbers to BigDecimal using the strings ‘Infinity’, ‘+Infinity’ and ‘-Infinity’ (case-sensitive)

Not a Number

When a computation results in an undefined value, the special value NaN (for ‘not a number’) is returned.

Example:

BigDecimal.new(“0.0”) / BigDecimal.new(“0.0”) -> NaN

You can also create undefined values. NaN is never considered to be the same as any other value, even NaN itself:

n = BigDecimal.new(‘NaN’)

n == 0.0 -> nil

n == n -> nil

Positive and negative zero

If a computation results in a value which is too small to be represented as a BigDecimal within the currently specified limits of precision, zero must be returned.

If the value which is too small to be represented is negative, a BigDecimal value of negative zero is returned. If the value is positive, a value of positive zero is returned.

BigDecimal.new(“1.0”) / BigDecimal.new(“-Infinity”) -> -0.0

BigDecimal.new(“1.0”) / BigDecimal.new(“Infinity”) -> 0.0

(See BigDecimal.mode for how to specify limits of precision.)

Note that -0.0 and 0.0 are considered to be the same for the purposes of comparison.

Note also that in mathematics, there is no particular concept of negative or positive zero; true mathematical zero has no sign.

Constant Summary collapse

BASE =

Base value used in internal calculations. On a 32 bit system, BASE is 10000, indicating that calculation is done in groups of 4 digits. (If it were larger, BASE**2 wouldn’t fit in 32 bits, so you couldn’t guarantee that two groups could always be multiplied together without overflow.)

INT2FIX((S_INT)VpBaseVal())
EXCEPTION_ALL =

Determines whether overflow, underflow or zero divide result in an exception being thrown. See BigDecimal.mode.

0xff
EXCEPTION_NaN =

Determines what happens when the result of a computation is not a number (NaN). See BigDecimal.mode.

0x02
EXCEPTION_INFINITY =

Determines what happens when the result of a computation is infinity. See BigDecimal.mode.

0x01
EXCEPTION_UNDERFLOW =

Determines what happens when the result of a computation is an underflow (a result too small to be represented). See BigDecimal.mode.

0x04
EXCEPTION_OVERFLOW =

Determines what happens when the result of a computation is an underflow (a result too large to be represented). See BigDecimal.mode.

0x01
EXCEPTION_ZERODIVIDE =

Determines what happens when a division by zero is performed. See BigDecimal.mode.

0x01
ROUND_MODE =

Determines what happens when a result must be rounded in order to fit in the appropriate number of significant digits. See BigDecimal.mode.

0x100
ROUND_UP =

Indicates that values should be rounded away from zero. See BigDecimal.mode.

1
ROUND_DOWN =

Indicates that values should be rounded towards zero. See BigDecimal.mode.

2
ROUND_HALF_UP =

Indicates that digits >= 5 should be rounded up, others rounded down. See BigDecimal.mode.

3
ROUND_HALF_DOWN =

Indicates that digits >= 6 should be rounded up, others rounded down. See BigDecimal.mode.

4
ROUND_CEILING =

Round towards +infinity. See BigDecimal.mode.

5
ROUND_FLOOR =

Round towards -infinity. See BigDecimal.mode.

6
ROUND_HALF_EVEN =

Round towards the even neighbor. See BigDecimal.mode.

7
SIGN_NaN =

Indicates that a value is not a number. See BigDecimal.sign.

0
SIGN_POSITIVE_ZERO =

Indicates that a value is +0. See BigDecimal.sign.

1
SIGN_NEGATIVE_ZERO =

Indicates that a value is -0. See BigDecimal.sign.

-1
SIGN_POSITIVE_FINITE =

Indicates that a value is positive and finite. See BigDecimal.sign.

2
SIGN_NEGATIVE_FINITE =

Indicates that a value is negative and finite. See BigDecimal.sign.

-2
SIGN_POSITIVE_INFINITE =

Indicates that a value is positive and infinite. See BigDecimal.sign.

3
SIGN_NEGATIVE_INFINITE =

Indicates that a value is negative and infinite. See BigDecimal.sign.

-3

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._load(str) ⇒ Object

Internal method used to provide marshalling support. See the Marshal module.



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'bigdecimal.c', line 325

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_figObject

BigDecimal.double_fig

The BigDecimal.double_fig class method returns the number of digits a Float number is allowed to have. The result depends upon the CPU and OS in use.



257
258
259
260
261
# File 'bigdecimal.c', line 257

static VALUE
BigDecimal_double_fig(VALUE self)
{
    return INT2FIX(VpDblFig());
}

.induced_from(x) ⇒ Object



573
574
575
576
577
578
# File 'bigdecimal.c', line 573

static VALUE
BigDecimal_induced_from(VALUE self, VALUE x)
{
    Real *p = GetVpValue(x,1);
    return p->obj;
}

.limit(*args) ⇒ Object

BigDecimal.limit(digits)

Limit the number of significant digits in newly created BigDecimal numbers to the specified value. Rounding is performed as necessary, as specified by BigDecimal.mode.

A limit of 0, the default, means no upper limit.

The limit specified by this method takes priority over any limit specified to instance methods such as ceil, floor, truncate, or round.



1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
# File 'bigdecimal.c', line 1729

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(nFig==Qnil) return nCur;
        Check_Type(nFig, T_FIXNUM);
        nf = FIX2INT(nFig);
        if(nf<0) {
            rb_raise(rb_eArgError, "argument must be positive");
        }
        VpSetPrecLimit(nf);
    }
    return nCur;
}

.mode(*args) ⇒ Object

BigDecimal.mode(mode, value)

Controls handling of arithmetic exceptions and rounding. If no value is supplied, the current value is returned.

Six values of the mode parameter control the handling of arithmetic exceptions:

BigDecimal::EXCEPTION_NaN BigDecimal::EXCEPTION_INFINITY BigDecimal::EXCEPTION_UNDERFLOW BigDecimal::EXCEPTION_OVERFLOW BigDecimal::EXCEPTION_ZERODIVIDE BigDecimal::EXCEPTION_ALL

For each mode parameter above, if the value set is false, computation continues after an arithmetic exception of the appropriate type. When computation continues, results are as follows:

EXCEPTION_NaN

NaN

EXCEPTION_INFINITY

+infinity or -infinity

EXCEPTION_UNDERFLOW

0

EXCEPTION_OVERFLOW

+infinity or -infinity

EXCEPTION_ZERODIVIDE

+infinity or -infinity

One value of the mode parameter controls the rounding of numeric values: BigDecimal::ROUND_MODE. The values it can take are:

ROUND_UP

round away from zero

ROUND_DOWN

round towards zero (truncate)

ROUND_HALF_UP

round up if the appropriate digit >= 5, otherwise truncate (default)

ROUND_HALF_DOWN

round up if the appropriate digit >= 6, otherwise truncate

ROUND_HALF_EVEN

round towards the even neighbor (Banker’s rounding)

ROUND_CEILING

round towards positive infinity (ceil)

ROUND_FLOOR

round towards negative infinity (floor)



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'bigdecimal.c', line 388

static VALUE
BigDecimal_mode(int argc, VALUE *argv, VALUE self)
{
    VALUE which;
    VALUE val;
    unsigned long f,fo;
 
    if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil;

    Check_Type(which, T_FIXNUM);
    f = (unsigned long)FIX2INT(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_eTypeError, "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))));
        }
        if(f&VP_EXCEPTION_NaN) {
            VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
                           (fo&(~VP_EXCEPTION_NaN))));
        }
        fo = VpGetException();
        return INT2FIX(fo);
    }
    if(VP_ROUND_MODE==f) {
        /* Rounding mode setting */
        fo = VpGetRoundMode();
        if(val==Qnil) return INT2FIX(fo);
        Check_Type(val, T_FIXNUM);
        if(!VpIsRoundMode(FIX2INT(val))) {
            rb_raise(rb_eTypeError, "invalid rounding mode");
            return Qnil;
        }
        fo = VpSetRoundMode((unsigned long)FIX2INT(val));
        return INT2FIX(fo);
    }
    rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
    return Qnil;
}

.new(*args) ⇒ Object

new(initial, digits)

Create a new BigDecimal object.

initial

The initial value, as a String. Spaces are ignored, unrecognized characters terminate the value.

digits

The number of significant digits, as a Fixnum. If omitted or 0, the number of significant digits is determined from the initial value.

The actual number of significant digits used in computation is usually larger than the specified number.



1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
# File 'bigdecimal.c', line 1698

static VALUE
BigDecimal_new(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *pv;
    S_LONG mf;
    VALUE  nFig;
    VALUE  iniValue;

    if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
        mf = 0;
    } else {
        mf = GetPositiveInt(nFig);
    }
    SafeStringValue(iniValue);
    GUARD_OBJ(pv,VpNewRbClass(mf, RSTRING_PTR(iniValue),self));
    return ToValue(pv);
}

.verObject

Returns the BigDecimal version number.

Ruby 1.8.0 returns 1.0.0. Ruby 1.8.1 thru 1.8.3 return 1.0.1.



162
163
164
165
166
167
168
169
170
# File 'bigdecimal.c', line 162

static VALUE
BigDecimal_version(VALUE self)
{
    /*
     * 1.0.0: Ruby 1.8.0
     * 1.0.1: Ruby 1.8.1
    */
    return rb_str_new2("1.0.1");
}

Instance Method Details

#%Object

%: a%b = a - (a.to_f/b).floor * b



996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
# File 'bigdecimal.c', line 996

static VALUE
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
{
    ENTER(3);
    VALUE obj;
    Real *div=NULL, *mod=NULL;

    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
    if(obj!=(VALUE)0) return obj;
    SAVE(div);SAVE(mod);
    return ToValue(mod);
}

#*(r) ⇒ Object

mult(value, digits)

Multiply by the specified value.

e.g.

c = a.mult(b,n)
c = a * b
digits

If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.



857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
# File 'bigdecimal.c', line 857

static VALUE
BigDecimal_mult(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    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);
}

#**(p) ⇒ Object

power(n)

Returns the value raised to the power of n. Note that n must be an Integer.

Also available as the operator **



1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
# File 'bigdecimal.c', line 1643

static VALUE
BigDecimal_power(VALUE self, VALUE p)
{
    ENTER(5);
    Real *x, *y;
    S_LONG mp, ma, n;

    Check_Type(p, T_FIXNUM);
    n = FIX2INT(p);
    ma = n;
    if(ma < 0)  ma = -ma;
    if(ma == 0) ma = 1;

    GUARD_OBJ(x,GetVpValue(self,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, n);
    return ToValue(y);
}

#+(r) ⇒ Object

add(value, digits)

Add the specified value.

e.g.

c = a.add(b,n)
c = a + b
digits

If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
# File 'bigdecimal.c', line 653

static VALUE
BigDecimal_add(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;
    GUARD_OBJ(a,GetVpValue(self,1));
    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==(-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);
}

#+@Object



636
637
638
639
640
# File 'bigdecimal.c', line 636

static VALUE
BigDecimal_uplus(VALUE self)
{
    return self;
}

#-(r) ⇒ Object

sub(value, digits)

Subtract the specified value.

e.g.

c = a.sub(b,n)
c = a - b
digits

If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.



691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'bigdecimal.c', line 691

static VALUE
BigDecimal_sub(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    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==(-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);
}

#-@Object



835
836
837
838
839
840
841
842
843
844
# File 'bigdecimal.c', line 835

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);
}

#/Object

For c = self/r: with round operation



912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
# File 'bigdecimal.c', line 912

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(r!=(VALUE)0) 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],(VpBaseVal()*res->frac[0])/div->frac[0]);
    }
    return ToValue(c);
}

#<(r) ⇒ Object

a < b

Returns true if a is less than b. Values may be coerced to perform the comparison (see ==, coerce).



793
794
795
796
797
# File 'bigdecimal.c', line 793

static VALUE
BigDecimal_lt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '<');
}

#<=(r) ⇒ Object

a <= b

Returns true if a is less than or equal to b. Values may be coerced to perform the comparison (see ==, coerce).



805
806
807
808
809
# File 'bigdecimal.c', line 805

static VALUE
BigDecimal_le(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'L');
}

#<=>(r) ⇒ Object

The comparison operator. a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.



765
766
767
768
769
# File 'bigdecimal.c', line 765

static VALUE
BigDecimal_comp(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '*');
}

#==(r) ⇒ Object

Tests for value equality; returns true if the values are equal.

The == and === operators and the eql? method have the same implementation for BigDecimal.

Values may be coerced to perform the comparison:

BigDecimal.new(‘1.0’) == 1.0 -> true



781
782
783
784
785
# File 'bigdecimal.c', line 781

static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

#===(r) ⇒ Object

Tests for value equality; returns true if the values are equal.

The == and === operators and the eql? method have the same implementation for BigDecimal.

Values may be coerced to perform the comparison:

BigDecimal.new(‘1.0’) == 1.0 -> true



781
782
783
784
785
# File 'bigdecimal.c', line 781

static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

#>(r) ⇒ Object

a > b

Returns true if a is greater than b. Values may be coerced to perform the comparison (see ==, coerce).



817
818
819
820
821
# File 'bigdecimal.c', line 817

static VALUE
BigDecimal_gt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '>');
}

#>=(r) ⇒ Object

a >= b

Returns true if a is greater than or equal to b. Values may be coerced to perform the comparison (see ==, coerce)



829
830
831
832
833
# File 'bigdecimal.c', line 829

static VALUE
BigDecimal_ge(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'G');
}

#_dump(*args) ⇒ Object



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'bigdecimal.c', line 305

static VALUE
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    char sz[50];
    Real *vp;
    char *psz;
    VALUE dummy;
    rb_scan_args(argc, argv, "01", &dummy);
    GUARD_OBJ(vp,GetVpValue(self,1));
    sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
    psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
    sprintf(psz,"%s",sz);
    VpToString(vp, psz+strlen(psz), 0, 0);
    return rb_str_new2(psz);
}

#absObject

Returns the absolute value.

BigDecimal(‘5’).abs -> 5

BigDecimal(‘-3’).abs -> 3



1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
# File 'bigdecimal.c', line 1189

static VALUE
BigDecimal_abs(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpAsgn(c, a, 1);
    VpChangeSign(c,(S_INT)1);
    return ToValue(c);
}

#add(b, n) ⇒ Object



1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
# File 'bigdecimal.c', line 1132

static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real   *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_add(self,b);
    else {
       U_LONG pl = VpSetPrecLimit(0);
       VALUE   c = BigDecimal_add(self,b);
       VpSetPrecLimit(pl);
       GUARD_OBJ(cv,GetVpValue(c,1));
       VpLeftRound(cv,VpGetRoundMode(),mx);
       return ToValue(cv);
    }
}

#ceil(*args) ⇒ Object

ceil(n)

Return the smallest integer greater than or equal to the value, as a BigDecimal.

BigDecimal(‘3.14159’).ceil -> 4

BigDecimal(‘-9.1’).ceil -> -9

If n is specified and positive, the fractional part of the result has no more than that many digits.

If n is specified and negative, at least that many digits to the left of the decimal point will be 0 in the result.

BigDecimal(‘3.14159’).ceil(3) -> 3.142

BigDecimal(‘13345.234’).ceil(-2) -> 13400.0



1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
# File 'bigdecimal.c', line 1432

static VALUE
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;
    int iLoc;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(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);
    return ToValue(c);
}

#coerce(other) ⇒ Object

The coerce method provides support for Ruby type coercion. It is not enabled by default.

This means that binary operations like + * / or - can often be performed on a BigDecimal and an object of another type, if the other object can be coerced into a BigDecimal value.

e.g. a = BigDecimal.new(“1.0”) b = a / 2.0 -> 0.5

Note that coercing a String to a BigDecimal is not supported by default; it requires a special compile-time option when building Ruby.



621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'bigdecimal.c', line 621

static VALUE
BigDecimal_coerce(VALUE self, VALUE other)
{
    ENTER(2);
    VALUE obj;
    Real *b;
    if(TYPE(other) == T_FLOAT) {
       obj = rb_assoc_new(other, BigDecimal_to_f(self));
    } else {
       GUARD_OBJ(b,GetVpValue(other,1));
       obj = rb_assoc_new(b->obj, self);
    }
    return obj;
}

#div(*args) ⇒ Object



1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
# File 'bigdecimal.c', line 1096

static VALUE
BigDecimal_div2(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    VALUE b,n;
    int na = rb_scan_args(argc,argv,"11",&b,&n);
    if(na==1) { /* div in Float sense */
       VALUE obj;
       Real *div=NULL;
       Real *mod;
       obj = BigDecimal_DoDivmod(self,b,&div,&mod);
       if(obj!=(VALUE)0) return obj;
       return ToValue(div);
    } else {    /* div in BigDecimal sense */
       U_LONG ix = (U_LONG)GetPositiveInt(n);
       if(ix==0) return BigDecimal_div(self,b);
       else {
          Real *res=NULL;
          Real *av=NULL, *bv=NULL, *cv=NULL;
          U_LONG mx = (ix+VpBaseFig()*2);
          U_LONG pl = VpSetPrecLimit(0);

          GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
          GUARD_OBJ(av,GetVpValue(self,1));
          GUARD_OBJ(bv,GetVpValue(b,1));
          mx = av->Prec + bv->Prec + 2;
          if(mx <= cv->MaxPrec) mx = cv->MaxPrec+1;
          GUARD_OBJ(res,VpCreateRbObject((mx * 2  + 2)*VpBaseFig(), "#0"));
          VpDivd(cv,res,av,bv);
          VpSetPrecLimit(pl);
          VpLeftRound(cv,VpGetRoundMode(),ix);
          return ToValue(cv);
       }
    }
}

#divmod(r) ⇒ Object

Divides by the specified value, and returns the quotient and modulus as BigDecimal numbers. The quotient is rounded towards negative infinity.

For example:

require ‘bigdecimal’

a = BigDecimal.new(“42”) b = BigDecimal.new(“9”)

q,m = a.divmod(b)

c = q * b + m

a == c -> true

The quotient q is (a/b).floor, and the modulus is the amount that must be added to q * b to get a.



1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
# File 'bigdecimal.c', line 1082

static VALUE
BigDecimal_divmod(VALUE self, VALUE r)
{
    ENTER(5);
    VALUE obj;
    Real *div=NULL, *mod=NULL;

    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
    if(obj!=(VALUE)0) return obj;
    SAVE(div);SAVE(mod);
    obj = rb_assoc_new(ToValue(div), ToValue(mod));
    return obj;
}

#eql?(r) ⇒ Boolean

Tests for value equality; returns true if the values are equal.

The == and === operators and the eql? method have the same implementation for BigDecimal.

Values may be coerced to perform the comparison:

BigDecimal.new(‘1.0’) == 1.0 -> true

Returns:

  • (Boolean)


781
782
783
784
785
# File 'bigdecimal.c', line 781

static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

#exponentObject

Returns the exponent of the BigDecimal number, as an Integer.

If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string of digits with no leading zeros, then n is the exponent.



1597
1598
1599
1600
1601
1602
# File 'bigdecimal.c', line 1597

static VALUE
BigDecimal_exponent(VALUE self)
{
    S_LONG e = VpExponent10(GetVpValue(self,1));
    return INT2NUM(e);
}

#finite?Boolean

Returns True if the value is finite (not NaN or infinite)

Returns:

  • (Boolean)


504
505
506
507
508
509
510
511
# File 'bigdecimal.c', line 504

static VALUE
BigDecimal_IsFinite(VALUE self)
{
    Real *p = GetVpValue(self,1);
    if(VpIsNaN(p)) return Qfalse;
    if(VpIsInf(p)) return Qfalse;
    return Qtrue;
}

#fixObject

Return the integer part of the number.



1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
# File 'bigdecimal.c', line 1230

static VALUE
BigDecimal_fix(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG 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(*args) ⇒ Object

floor(n)

Return the largest integer less than or equal to the value, as a BigDecimal.

BigDecimal(‘3.14159’).floor -> 3

BigDecimal(‘-9.1’).floor -> -10

If n is specified and positive, the fractional part of the result has no more than that many digits.

If n is specified and negative, at least that many digits to the left of the decimal point will be 0 in the result.

BigDecimal(‘3.14159’).floor(3) -> 3.141

BigDecimal(‘13345.234’).floor(-2) -> 13300.0



1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
# File 'bigdecimal.c', line 1388

static VALUE
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;
    int iLoc;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(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);
    return ToValue(c);
}

#fracObject

Return the fractional part of the number.



1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
# File 'bigdecimal.c', line 1355

static VALUE
BigDecimal_frac(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    U_LONG mx;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpFrac(c, a);
    return ToValue(c);
}

#hashObject



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'bigdecimal.c', line 285

static VALUE
BigDecimal_hash(VALUE self)
{
    ENTER(1);
    Real *p;
    U_LONG hash,i;

    GUARD_OBJ(p,GetVpValue(self,1));
    hash = (U_LONG)p->sign;
    /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
    if(hash==2) {
        for(i = 0; i < p->Prec;i++) {
            hash = 31 * hash + p->frac[i];
            hash ^= p->frac[i];
        }
        hash += p->exponent;
    }
    return INT2FIX(hash);
}

#infinite?Boolean

Returns True if the value is infinite

Returns:

  • (Boolean)


494
495
496
497
498
499
500
501
# File 'bigdecimal.c', line 494

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;
}

#inspectObject

Returns debugging information about the value as a string of comma-separated values in angle brackets with a leading #:

BigDecimal.new(“1234.5678”).inspect -> “#<BigDecimal:b7ea1130,‘0.12345678E4’,8(12)>”

The first part is the address, the second is the value as a string, and the final part ss(mm) is the current number of significant digits and the maximum number of significant digits, respectively.



1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
# File 'bigdecimal.c', line 1614

static VALUE
BigDecimal_inspect(VALUE self)
{
    ENTER(5);
    Real *vp;
    VALUE obj;
    unsigned int nc;
    char *psz1;
    char *pszAll;

    GUARD_OBJ(vp,GetVpValue(self,1));
    nc = VpNumOfChars(vp,"E");
    nc +=(nc + 9) / 10;

    psz1   = ALLOCA_N(char,nc);
    pszAll = ALLOCA_N(char,nc+256);
    VpToString(vp, psz1, 10, 0);
    sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
    obj = rb_str_new2(pszAll);
    return obj;
}

#moduloObject

%: a%b = a - (a.to_f/b).floor * b



996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
# File 'bigdecimal.c', line 996

static VALUE
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
{
    ENTER(3);
    VALUE obj;
    Real *div=NULL, *mod=NULL;

    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
    if(obj!=(VALUE)0) return obj;
    SAVE(div);SAVE(mod);
    return ToValue(mod);
}

#mult(b, n) ⇒ Object



1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
# File 'bigdecimal.c', line 1166

static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_mult(self,b);
    else {
       U_LONG 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?Boolean

Returns True if the value is Not a Number

Returns:

  • (Boolean)


485
486
487
488
489
490
491
# File 'bigdecimal.c', line 485

static VALUE
BigDecimal_IsNaN(VALUE self)
{
    Real *p = GetVpValue(self,1);
    if(VpIsNaN(p))  return Qtrue;
    return Qfalse;
}

#nonzero?Boolean

Returns True if the value is non-zero.

Returns:

  • (Boolean)


755
756
757
758
759
760
# File 'bigdecimal.c', line 755

static VALUE
BigDecimal_nonzero(VALUE self)
{
    Real *a = GetVpValue(self,1);
    return VpIsZero(a) ? Qnil : self;
}

#power(p) ⇒ Object

power(n)

Returns the value raised to the power of n. Note that n must be an Integer.

Also available as the operator **



1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
# File 'bigdecimal.c', line 1643

static VALUE
BigDecimal_power(VALUE self, VALUE p)
{
    ENTER(5);
    Real *x, *y;
    S_LONG mp, ma, n;

    Check_Type(p, T_FIXNUM);
    n = FIX2INT(p);
    ma = n;
    if(ma < 0)  ma = -ma;
    if(ma == 0) ma = 1;

    GUARD_OBJ(x,GetVpValue(self,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, n);
    return ToValue(y);
}

#precsObject

precs

Returns an Array of two Integer values.

The first value is the current number of significant digits in the BigDecimal. The second value is the maximum number of significant digits for the BigDecimal.



272
273
274
275
276
277
278
279
280
281
282
283
# File 'bigdecimal.c', line 272

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;
}

#quoObject

For c = self/r: with round operation



912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
# File 'bigdecimal.c', line 912

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(r!=(VALUE)0) 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],(VpBaseVal()*res->frac[0])/div->frac[0]);
    }
    return ToValue(c);
}

#remainderObject

remainder



1053
1054
1055
1056
1057
1058
1059
1060
1061
# File 'bigdecimal.c', line 1053

static VALUE
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
{
    VALUE  f;
    Real  *d,*rv=0;
    f = BigDecimal_divremain(self,r,&d,&rv);
    if(f!=(VALUE)0) return f;
    return ToValue(rv);
}

#round(*args) ⇒ Object

round(n,mode)

Round to the nearest 1 (by default), returning the result as a BigDecimal.

BigDecimal(‘3.14159’).round -> 3

BigDecimal(‘8.7’).round -> 9

If n is specified and positive, the fractional part of the result has no more than that many digits.

If n is specified and negative, at least that many digits to the left of the decimal point will be 0 in the result.

BigDecimal(‘3.14159’).round(3) -> 3.142

BigDecimal(‘13345.234’).round(-2) -> 13300.0

The value of the optional mode argument can be used to determine how rounding is performed; see BigDecimal.mode.



1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
# File 'bigdecimal.c', line 1266

static VALUE
BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real   *c, *a;
    int    iLoc = 0;
    U_LONG mx;
    VALUE  vLoc;
    VALUE  vRound;
    U_LONG pl;

    int    sw = VpGetRoundMode();

    int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound);
    switch(na) {
    case 0:
        iLoc = 0;
        break;
    case 1:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        break;
    case 2:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        Check_Type(vRound, T_FIXNUM);
        sw   = FIX2INT(vRound);
        if(!VpIsRoundMode(sw)) {
            rb_raise(rb_eTypeError, "invalid rounding mode");
            return Qnil;
        }
        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);
    return ToValue(c);
}

#signObject

Returns the sign of the value.

Returns a positive value if > 0, a negative value if < 0, and a zero if == 0.

The specific value returned indicates the type and sign of the BigDecimal, as follows:

BigDecimal::SIGN_NaN

value is Not a Number

BigDecimal::SIGN_POSITIVE_ZERO

value is +0

BigDecimal::SIGN_NEGATIVE_ZERO

value is -0

BigDecimal::SIGN_POSITIVE_INFINITE

value is +infinity

BigDecimal::SIGN_NEGATIVE_INFINITE

value is -infinity

BigDecimal::SIGN_POSITIVE_FINITE

value is positive

BigDecimal::SIGN_NEGATIVE_FINITE

value is negative



1764
1765
1766
1767
1768
1769
# File 'bigdecimal.c', line 1764

static VALUE
BigDecimal_sign(VALUE self)
{ /* sign */
    int s = GetVpValue(self,1)->sign;
    return INT2FIX(s);
}

#splitObject

Splits a BigDecimal number into four parts, returned as an array of values.

The first value represents the sign of the BigDecimal, and is -1 or 1, or 0 if the BigDecimal is Not a Number.

The second value is a string representing the significant digits of the BigDecimal, with no leading zeros.

The third value is the base used for arithmetic (currently always 10) as an Integer.

The fourth value is an Integer exponent.

If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the string of significant digits with no leading zeros, and n is the exponent.

From these values, you can translate a BigDecimal to a float as follows:

sign, significant_digits, base, exponent = a.split
f = sign * "0.#{significant_digits}".to_f * (base ** exponent)

(Note that the to_f method is provided as a more convenient way to translate a BigDecimal to a Float.)



1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
# File 'bigdecimal.c', line 1564

static VALUE
BigDecimal_split(VALUE self)
{
    ENTER(5);
    Real *vp;
    VALUE obj,obj1;
    S_LONG e;
    S_LONG s;
    char *psz1;

    GUARD_OBJ(vp,GetVpValue(self,1));
    psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
    VpSzMantissa(vp,psz1);
    s = 1;
    if(psz1[0]=='-') {
        s = -1; ++psz1;
    }
    if(psz1[0]=='N') s=0; /* NaN */
    e = VpExponent10(vp);
    obj1 = rb_str_new2(psz1);
    obj  = rb_ary_new2(4);
    rb_ary_push(obj, INT2FIX(s));
    rb_ary_push(obj, obj1);
    rb_ary_push(obj, INT2FIX(10));
    rb_ary_push(obj, INT2NUM(e));
    return obj;
}

#sqrt(nFig) ⇒ Object

sqrt(n)

Returns the square root of the value.

If n is specified, returns at least that many significant digits.



1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
# File 'bigdecimal.c', line 1211

static VALUE
BigDecimal_sqrt(VALUE self, VALUE nFig)
{
    ENTER(5);
    Real *c, *a;
    S_INT mx, n;

    GUARD_OBJ(a,GetVpValue(self,1));
    mx = a->Prec *(VpBaseFig() + 1);

    n = GetPositiveInt(nFig) + VpDblFig() + 1;
    if(mx <= n) mx = n;
    GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
    VpSqrt(c, a);
    return ToValue(c);
}

#sub(b, n) ⇒ Object



1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
# File 'bigdecimal.c', line 1149

static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    U_LONG mx = (U_LONG)GetPositiveInt(n);
    if(mx==0) return BigDecimal_sub(self,b);
    else {
       U_LONG 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_digitsObject

Converts a BigDecimal to a String of the form “nnnnnn.mmm”. This method is deprecated; use BigDecimal#to_s(“F”) instead.



33
34
35
36
37
38
39
40
41
# File 'lib/bigdecimal/util.rb', line 33

def to_digits
   if self.nan? || self.infinite? || self.zero?
      self.to_s
   else
     i       = self.to_i.to_s
     s,f,y,z = self.frac.split
     i + "." + ("0"*(-z)) + f
   end
end

#to_fObject

Returns a new Float object having approximately the same value as the BigDecimal number. Normal accuracy limits and built-in errors of binary Float arithmetic apply.



584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
# File 'bigdecimal.c', line 584

static VALUE
BigDecimal_to_f(VALUE self)
{
    ENTER(1);
    Real *p;
    double d;
    S_LONG e;
    char *buf;

    GUARD_OBJ(p,GetVpValue(self,1));
    if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
    buf = ALLOCA_N(char,(unsigned int)VpNumOfChars(p,"E"));
    VpToString(p, buf, 0, 0);
    errno = 0;
    d = strtod(buf, 0);
    if(errno == ERANGE) {
       VpException(VP_EXCEPTION_OVERFLOW,"BigDecimal to Float conversion",0);
       if(d>0.0) return rb_float_new(DBL_MAX);
       else      return rb_float_new(-DBL_MAX);
    }
    return rb_float_new(d);
}

#to_iObject

Returns the value as an integer (Fixnum or Bignum).

If the BigNumber is infinity or NaN, returns nil.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'bigdecimal.c', line 517

static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    int e,n,i,nf;
    U_LONG v,b,j;
    char *psz,*pch;
    Real *p;

    GUARD_OBJ(p,GetVpValue(self,1));

    /* Infinity or NaN not converted. */
    if(VpIsNaN(p)) {
       VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
       return Qnil;
    } else if(VpIsPosInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
       return Qnil;
    } else if(VpIsNegInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
       return Qnil;
    }

    e = VpExponent10(p);
    if(e<=0) return INT2FIX(0);
    nf = VpBaseFig();
    if(e<=nf) {
        e = VpGetSign(p)*p->frac[0];
        return INT2FIX(e);
    }
    psz = ALLOCA_N(char,(unsigned int)(e+nf+2));

    n = (e+nf-1)/nf;
    pch = psz;
    if(VpGetSign(p)<0) *pch++ = '-';
    for(i=0;i<n;++i) {
        b = VpBaseVal()/10;
        if(i>=(int)p->Prec) {
            while(b) {
                *pch++ = '0';
                b /= 10;
            }
            continue;
        }
        v = p->frac[i];
        while(b) {
            j = v/b;
            *pch++ = (char)(j + '0');
            v -= j*b;
            b /= 10;
        }
    }
    *pch++ = 0;
    return rb_cstr2inum(psz,10);
}

#to_intObject

Returns the value as an integer (Fixnum or Bignum).

If the BigNumber is infinity or NaN, returns nil.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'bigdecimal.c', line 517

static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    int e,n,i,nf;
    U_LONG v,b,j;
    char *psz,*pch;
    Real *p;

    GUARD_OBJ(p,GetVpValue(self,1));

    /* Infinity or NaN not converted. */
    if(VpIsNaN(p)) {
       VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
       return Qnil;
    } else if(VpIsPosInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
       return Qnil;
    } else if(VpIsNegInf(p)) {
       VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
       return Qnil;
    }

    e = VpExponent10(p);
    if(e<=0) return INT2FIX(0);
    nf = VpBaseFig();
    if(e<=nf) {
        e = VpGetSign(p)*p->frac[0];
        return INT2FIX(e);
    }
    psz = ALLOCA_N(char,(unsigned int)(e+nf+2));

    n = (e+nf-1)/nf;
    pch = psz;
    if(VpGetSign(p)<0) *pch++ = '-';
    for(i=0;i<n;++i) {
        b = VpBaseVal()/10;
        if(i>=(int)p->Prec) {
            while(b) {
                *pch++ = '0';
                b /= 10;
            }
            continue;
        }
        v = p->frac[i];
        while(b) {
            j = v/b;
            *pch++ = (char)(j + '0');
            v -= j*b;
            b /= 10;
        }
    }
    *pch++ = 0;
    return rb_cstr2inum(psz,10);
}

#to_rObject

Converts a BigDecimal to a Rational.



44
45
46
47
48
49
50
51
52
53
# File 'lib/bigdecimal/util.rb', line 44

def to_r 
   sign,digits,base,power = self.split
   numerator = sign*digits.to_i
   denomi_power = power - digits.size # base is always 10
   if denomi_power < 0
      Rational(numerator,base ** (-denomi_power))
   else
      Rational(numerator * (base ** denomi_power),1)
   end
end

#to_s(*args) ⇒ Object

to_s(s)

Converts the value to a string.

The default format looks like 0.xxxxEnn.

The optional parameter s consists of either an integer; or an optional ‘+’ or ‘ ’, followed by an optional number, followed by an optional ‘E’ or ‘F’.

If there is a ‘+’ at the start of s, positive values are returned with a leading ‘+’.

A space at the start of s returns positive values with a leading space.

If s contains a number, a space is inserted after each group of that many fractional digits.

If s ends with an ‘E’, engineering notation (0.xxxxEnn) is used.

If s ends with an ‘F’, conventional floating point notation is used.

Examples:

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’



1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
# File 'bigdecimal.c', line 1487

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;
    char  *psz;
    char   ch;
    U_LONG nc;
    S_INT  mc = 0;
    VALUE  f;

    GUARD_OBJ(vp,GetVpValue(self,1));
    
    if(rb_scan_args(argc,argv,"01",&f)==1) {
        if(TYPE(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  = GetPositiveInt(f);
        }
    }
    if(fmt) {
        nc = VpNumOfChars(vp,"F");
    } else {
        nc = VpNumOfChars(vp,"E");
    }
    if(mc>0) nc += (nc + mc - 1) / mc + 1;

    psz = ALLOCA_N(char,(unsigned int)nc);

    if(fmt) {
        VpToFString(vp, psz, mc, fPlus);
    } else {
        VpToString (vp, psz, mc, fPlus);
    }
    return rb_str_new2(psz);
}

#truncate(*args) ⇒ Object

truncate(n)

Truncate to the nearest 1, returning the result as a BigDecimal.

BigDecimal(‘3.14159’).truncate -> 3

BigDecimal(‘8.7’).truncate -> 8

If n is specified and positive, the fractional part of the result has no more than that many digits.

If n is specified and negative, at least that many digits to the left of the decimal point will be 0 in the result.

BigDecimal(‘3.14159’).truncate(3) -> 3.141

BigDecimal(‘13345.234’).truncate(-2) -> 13300.0



1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
# File 'bigdecimal.c', line 1328

static VALUE
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    U_LONG mx;
    VALUE vLoc;
    U_LONG pl = VpSetPrecLimit(0);

    if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
        iLoc = 0;
    } else {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(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 */
    return ToValue(c);
}

#zero?Boolean

Returns True if the value is zero.

Returns:

  • (Boolean)


747
748
749
750
751
752
# File 'bigdecimal.c', line 747

static VALUE
BigDecimal_zero(VALUE self)
{
    Real *a = GetVpValue(self,1);
    return VpIsZero(a) ? Qtrue : Qfalse;
}