Spec-Zone.ru › Ruby 2.7

класс BigDecimal

Родитель:
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("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 более точна, чем обычная двоичная арифметика с плавающей точкой, она требует некоторых специальных значений.

Бесконечность

BigDecimal иногда нужно возвращать бесконечность, например, если вы делите значение на ноль.

BigDecimal("1.0") / BigDecimal("0.0")  #=> Infinity
BigDecimal("-1.0") / BigDecimal("0.0")  #=> -Infinity

Вы можете представлять бесконечные числа для BigDecimal с помощью строк 'Infinity', '+Infinity' и '-Infinity' (регистрозависимые).

Не число (NaN)

Когда вычисление приводит к неопределённому значению, возвращается специальное значение NaN (для 'не числа').

Пример:

BigDecimal("0.0") / BigDecimal("0.0") #=> NaN

Вы также можете создать неопределённые значения.

NaN никогда не считается равным ни одному другому значению, даже самому себе:

n = BigDecimal('NaN')
n == 0.0 #=> false
n == n #=> false

Положительный и отрицательный ноль

Если вычисление приводит к значению, которое слишком мало для представления как BigDecimal в пределах текущих заданных пределов точности, возвращается ноль.

Если значение, слишком малое для представления, отрицательное, возвращается значение отрицательного нуля.

BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0

Если значение положительное, возвращается значение положительного нуля.

BigDecimal("1.0") / BigDecimal("Infinity") #=> 0.0

(См. BigDecimal.mode о том, как задать пределы точности.)

Обратите внимание, что -0.0 и 0.0 считаются одинаковыми для целей сравнения.

Обратите также внимание, что в математике нет особой концепции отрицательного или положительного нуля; истинному математическому нулю знак не присущ.

bigdecimal/util

Когда вам требуется bigdecimal/util, метод to_d будет доступен для BigDecimal и родных классов Integer, Float, Rational и String:

require 'bigdecimal/util'

42.to_d         # => 0.42e2
0.5.to_d        # => 0.5e0
(2/3r).to_d(3)  # => 0.667e0
"0.5".to_d      # => 0.5e0

Лицензия

Авторские права (C) 2002 Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.

BigDecimal распространяется по лицензиям Ruby и 2-хпунктовой 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

Положительная бесконечность.

NAN

Значение 'Не число'.

ROUND_CEILING

Округляет до +Бесконечности. См. BigDecimal.mode.

ROUND_DOWN

Указывает, что значения должны округляться к нулю. См. BigDecimal.mode.

ROUND_FLOOR

Округляет к -Бесконечности. См. 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

Методы публичного класса

_load(p1) Показать исходный код
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));
    m /= VpBaseFig();
    if (m && pv->MaxPrec > m) {
        pv->MaxPrec = m+1;
    }
    return ToValue(pv);
}

Внутренний метод, используемый для поддержки маршаллирования. См. модуль Marshal.

double_fig Показать исходный код
static VALUE
BigDecimal_double_fig(VALUE self)
{
    return INT2FIX(VpDblFig());
}

Метод класса BigDecimal.double_fig возвращает количество цифр, которое разрешено иметь числу Float. Результат зависит от используемого процессора и операционной системы.

interpret_loosely(p1) Показать исходный код
static VALUE
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
{
    ENTER(1);
    char const *c_str;
    Real *pv;

    c_str = StringValueCStr(str);
    GUARD_OBJ(pv, VpAlloc(0, c_str, 0, 1));
    pv->obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, pv);
    RB_OBJ_FREEZE(pv->obj);
    return pv->obj;
}
json_create(object) Показать исходный код
# File ext/json/lib/json/add/bigdecimal.rb, line 11
def self.json_create(object)
  BigDecimal._load object['b']
end

Импортировать JSON маршаллированный объект.

Метод используется для поддержки маршаллирования JSON.

limit(digits) Показать исходный код
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;
}

Ограничить количество значащих цифр в новых числах BigDecimal заданным значением. Округление выполняется по необходимости, как указано в BigDecimal.mode.

Предел 0 (по умолчанию) означает отсутствие верхнего предела.

Предел, указанный этим методом, имеет меньший приоритет по сравнению с любым пределом, указанным в методах экземпляра, таких как ceil, floor, truncate или round.

mode(mode, value) Показать исходный код
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::EXCEPTION_NaN BigDecimal::EXCEPTION_INFINITY BigDecimal::EXCEPTION_UNDERFLOW BigDecimal::EXCEPTION_OVERFLOW BigDecimal::EXCEPTION_ZERODIVIDE BigDecimal::EXCEPTION_ALL

Для каждого из вышеперечисленных параметров режима, если установленное значение ложно, вычисления продолжаются после возникновения соответствующего арифметического исключения. При продолжении вычислений результаты следующие:

EXCEPTION_NaN

NaN

EXCEPTION_INFINITY

+Бесконечность или -Бесконечность

EXCEPTION_UNDERFLOW

0

EXCEPTION_OVERFLOW

+Бесконечность или -Бесконечность

EXCEPTION_ZERODIVIDE

+Бесконечность или -Бесконечность

Одно значение параметра режима управляет округлением числовых значений: BigDecimal::ROUND_MODE. Возможные значения:

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

округление до положительной бесконечности (ceil)

ROUND_FLOOR, :floor

округление до отрицательной бесконечности (floor)

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

Выполнить предоставленный блок, но сохранить режим исключений

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

save_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.limit(100)
puts BigDecimal.limit
BigDecimal.save_limit do
    BigDecimal.limit(200)
    puts BigDecimal.limit
end
puts BigDecimal.limit
save_rounding_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.save_rounding_mode do
  BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
  puts BigDecimal.mode(BigDecimal::ROUND_MODE)
end

Для использования с BigDecimal::ROUND_*

См. BigDecimal.mode

Общедоступные методы экземпляров

a % b Показать исходный код
static VALUE
BigDecimal_mod(VALUE self, VALUE r) 

Возвращает остаток от деления на b.

См. BigDecimal#divmod.

mult(value, 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);
}

Умножение на указанное значение.

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с BigDecimal.mode.

a ** n → bigdecimal Показать исходный код
static VALUE
BigDecimal_power_op(VALUE self, VALUE exp)
{
    return BigDecimal_power(1, &exp, self);
}

Возвращает значение, возведённое в степень n.

См. BigDecimal#power.

add(value, 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);
}

Сложение указанного значения.

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с BigDecimal.mode.

+big_decimal → big_decimal Показать исходный код
static VALUE
BigDecimal_uplus(VALUE self)
{
    return self;
}

Возвращает само себя.

+BigDecimal('5')  #=> 0.5e1
a - b → bigdecimal Показать исходный код
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);
}

Вычитание указанного значения.

Например:

c = a - b

Точность значения результата зависит от типа b.

Если b является Float, точность результата равна Float::DIG+1.

Если b является BigDecimal, точность результата равна точности внутренней представления b с платформы. Таким образом, значение результата зависит от платформы.

-big_decimal → big_decimal Показать исходный код
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);
}

Возвращает отрицание self.

-BigDecimal('5')  #=> -0.5e1
a / b → bigdecimal Показать исходный код
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);
}

Деление на указанное значение.

См. BigDecimal#div.

a < b Показать исходный код
static VALUE
BigDecimal_lt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '<');
}

Возвращает true, если a меньше b.

Значения могут быть приведены к типу для сравнения (см. ==, BigDecimal#coerce).

a <= b Показать исходный код
static VALUE
BigDecimal_le(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'L');
}

Возвращает true, если a меньше или равно b.

Значения могут быть приведены к типу для сравнения (см. ==, BigDecimal#coerce).

<=>(p1) Показать исходный код
static VALUE
BigDecimal_comp(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '*');
}

Оператор сравнения. a <=> b равен 0, если a == b, 1, если a > b, -1, если a < b.

==(p1) Показать исходный код
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

Проверка равенства значений; возвращает true, если значения равны.

Операторы == и ===, а также метод eql? имеют одинаковую реализацию для BigDecimal.

Значения могут быть приведены к типу для сравнения:

BigDecimal('1.0') == 1.0  #=> true
===(p1) Показать исходный код
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

Проверка равенства значений; возвращает true, если значения равны.

Операторы == и ===, а также метод eql? имеют одинаковую реализацию для BigDecimal.

Значения могут быть приведены к типу для сравнения:

BigDecimal('1.0') == 1.0  #=> true
a > b Показать исходный код
static VALUE
BigDecimal_gt(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '>');
}

Возвращает true, если a больше b.

Значения могут быть приведены к типу для сравнения (см. ==, BigDecimal#coerce).

a >= b Показать исходный код
static VALUE
BigDecimal_ge(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, 'G');
}

Возвращает true, если a больше или равно b.

Значения могут быть приведены к типу для сравнения (см. ==, BigDecimal#coerce)

_dump Показать исходный код
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;
}

Метод Method используется для поддержки маршалинга.

inf = BigDecimal('Infinity')
  #=> Infinity
BigDecimal._load(inf._dump)
  #=> Infinity

См. модуль Marshal.

abs → big_decimal Показать исходный код
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);
}

Возвращает абсолютное значение в виде BigDecimal.

BigDecimal('5').abs  #=> 0.5e1
BigDecimal('-3').abs #=> 0.3e1
add(value, digits) Показать исходный код
static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = GetPrecisionInt(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);
    }
}

Сложение указанного значения.

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с BigDecimal.mode.

as_json(*) Показать исходный код
# File ext/json/lib/json/add/bigdecimal.rb, line 18
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'b'            => _dump,
  }
end

Сериализация объекта в Marshal.

Метод используется для маршалинга в JSON.

ceil(n) Показать исходный код
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);
}

Возвращает наименьшее целое число, большее или равное значению, в виде BigDecimal.

BigDecimal('3.14159').ceil #=> 4
BigDecimal('-9.1').ceil #=> -9

Если n указан и положителен, дробная часть результата содержит не более указанного числа цифр.

Если n указан и отрицателен, в результате будет не менее указанного количества нулей слева от десятичной точки.

BigDecimal('3.14159').ceil(3) #=> 3.142
BigDecimal('13345.234').ceil(-2) #=> 13400.0
clone() Показать исходный код
static VALUE
BigDecimal_clone(VALUE self)
{
  return self;
}
coerce(p1) Показать исходный код
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;
}

Метод coerce предоставляет поддержку приведения типов Ruby. Он не включен по умолчанию.

Это означает, что бинарные операции, такие как +, *, / или -, могут часто выполняться над BigDecimal и объектом другого типа, если другой объект может быть приведён к значению BigDecimal.

Например:

a = BigDecimal("1.0")
b = a / 2.0 #=> 0.5

Обратите внимание, что приведение String к BigDecimal не поддерживается по умолчанию; для этого требуется специальный параметр компиляции при сборке Ruby.

div(value, digits) → bigdecimal or integer Показать исходный код
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);
}

Деление на указанное значение.

digits

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с BigDecimal.mode.

Если digits равно 0, результат такой же, как для оператора / или quo.

Если digits не указано, результат — целое число, аналогично Float#div; см. также BigDecimal#divmod.

Примеры:

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
divmod(value) Показать исходный код
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"));
}

Делит на указанное значение и возвращает частное и остаток как числа 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.

dup() Показать исходный код
static VALUE
BigDecimal_clone(VALUE self)
{
  return self;
}
eql?(p1) Показать исходный код
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

Проверяет равенство значений; возвращает true, если значения равны.

Операторы == и ===, а также метод eql? имеют одинаковую реализацию для BigDecimal.

Значения могут быть приведены к типу для выполнения сравнения:

BigDecimal('1.0') == 1.0  #=> true
exponent() Показать исходный код
static VALUE
BigDecimal_exponent(VALUE self)
{
    ssize_t e = VpExponent10(GetVpValue(self, 1));
    return INT2NUM(e);
}

Возвращает показатель степени числа BigDecimal как Integer.

Если число можно представить как 0.xxxxxx*10**n, где xxxxxx — строка цифр без ведущих нулей, то n — показатель степени.

finite?() Показать исходный код
static VALUE
BigDecimal_IsFinite(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsNaN(p)) return Qfalse;
    if (VpIsInf(p)) return Qfalse;
    return Qtrue;
}

Возвращает True, если значение конечно (не NaN или бесконечно).

fix() Показать исходный код
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);
}

Возвращает целую часть числа как BigDecimal.

floor(n) Показать исходный код
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);
}

Возвращает наибольшее целое число, меньшее или равное значению, как 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
frac() Показать исходный код
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);
}

Возвращает дробную часть числа как BigDecimal.

hash Показать исходный код
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 ST2FIX(hash);
}

Создаёт хэш для данного BigDecimal.

Два BigDecimals с одинаковым знаком, дробной частью и показателем степени имеют одинаковый хэш.

infinite?() Показать исходный код
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;
}

Возвращает nil, -1 или +1 в зависимости от того, является ли значение конечным, -бесконечность или +бесконечность.

inspect() Показать исходный код
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;
}

Возвращает строковое представление self.

BigDecimal("1234.5678").inspect
  #=> "0.12345678e4"
modulo(b) Показать исходный код
static VALUE
BigDecimal_mod(VALUE self, VALUE r) 

Возвращает остаток от деления на b.

См. BigDecimal#divmod.

mult(value, digits) Показать исходный код
static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = GetPrecisionInt(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);
    }
}

Умножение на указанное значение.

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с BigDecimal.mode.

nan?() Показать исходный код
static VALUE
BigDecimal_IsNaN(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsNaN(p))  return Qtrue;
    return Qfalse;
}

Возвращает True, если значение — Not a Number.

nonzero?() Показать исходный код
static VALUE
BigDecimal_nonzero(VALUE self)
{
    Real *a = GetVpValue(self, 1);
    return VpIsZero(a) ? Qnil : self;
}

Возвращает self, если значение отлично от нуля, иначе nil.

power(n)
power(n, prec)
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);
}

Возвращает значение, возведённое в степень n.

Обратите внимание, что n должно быть Integer.

Также доступно как оператор **.

precs → array Показать исходный код
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;
}

Возвращает массив из двух Integer значений.

Первое значение — текущее количество значащих цифр в BigDecimal. Второе значение — максимальное количество значащих цифр для BigDecimal.

BigDecimal('5').precs #=> [9, 18]
quo(value) → bigdecimal Показать исходный код
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);
}

Деление на указанное значение.

См. BigDecimal#div.

remainder(value) Показать исходный код
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);
}

Возвращает остаток от деления на значение.

x.remainder(y) означает x-y*(x/y).truncate

round(n, 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);
}

Округление до ближайшего целого числа (по умолчанию), возвращая результат как BigDecimal, если n указано, или как 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.

BigDecimal('3.14159').round(3) #=> 3.142
BigDecimal('13345.234').round(-2) #=> 13300.0

Значение необязательного аргумента mode можно использовать для определения способа округления; см. BigDecimal.mode.

END_OF_DOCUMENT_MARKER
sign() Показать исходный код
static VALUE
BigDecimal_sign(VALUE self)
{ /* sign */
    int s = GetVpValue(self, 1)->sign;
    return INT2FIX(s);
}

Возвращает знак значения.

Возвращает положительное значение, если > 0, отрицательное значение, если < 0, и ноль, если == 0.

Конкретное возвращаемое значение указывает тип и знак BigDecimal следующим образом:

BigDecimal::SIGN_NaN

значение равно Не Число

BigDecimal::SIGN_POSITIVE_ZERO

значение равно +0

BigDecimal::SIGN_NEGATIVE_ZERO

значение равно -0

BigDecimal::SIGN_POSITIVE_INFINITE

значение равно +Бесконечность

BigDecimal::SIGN_NEGATIVE_INFINITE

значение равно -Бесконечность

BigDecimal::SIGN_POSITIVE_FINITE

значение положительное

BigDecimal::SIGN_NEGATIVE_FINITE

значение отрицательное

split() Показать исходный код
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;
}

Разбивает число BigDecimal на четыре части, возвращая их в виде массива значений.

Первое значение представляет знак BigDecimal и равно -1 или 1, или 0, если BigDecimal равно Не Число.

Второе значение — это строка, представляющая значащие цифры 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.)

sqrt(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 = GetPrecisionInt(nFig) + VpDblFig() + BASE_FIG;
    if (mx <= n) mx = n;
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSqrt(c, a);
    return ToValue(c);
}

Возвращает квадратный корень из значения.

Результат имеет по меньшей мере n значащих цифр.

sub(value, digits) → bigdecimal Показать исходный код
static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = GetPrecisionInt(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);
    }
}

Вычитает указанное значение.

Например:

c = a.sub(b,n)
digits

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого числа цифр в соответствии с BigDecimal.mode.

to_d → bigdecimal Показать исходный код
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 106
def to_d
  self
end

Возвращает self.

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_d                       # => 0.314e1
to_digits → string Показать исходный код
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 86
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

Преобразует BigDecimal в строку формата «nnnnnn.mmm». Этот метод устарел; используйте BigDecimal#to_s(“F”) вместо этого.

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_digits                  # => "3.14"
to_f() Показать исходный код
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);
}

Возвращает новый объект Float с примерно таким же значением, что и число BigDecimal. Применяются обычные ограничения точности и встроенные ошибки арифметики с плавающей точкой.

to_i() Показать исходный код
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;
    }
}

Возвращает значение как целое число Integer.

Если BigDecimal бесконечен или NaN, генерируется FloatDomainError.

to_int() Показать исходный код
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;
    }
}

Возвращает значение как целое число Integer.

Если BigDecimal бесконечен или NaN, генерируется FloatDomainError.

to_json(*args) Показать исходный код
# File ext/json/lib/json/add/bigdecimal.rb, line 26
def to_json(*args)
  as_json.to_json(*args)
end

Возвращает значение JSON.

to_r() Показать исходный код
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))));
    }
}

Преобразует BigDecimal в рациональное число Rational.

to_s(s) Показать исходный код
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_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;
}

Преобразует значение в строку.

По умолчанию формат похож на 0.xxxxEnn.

Необязательный параметр s состоит либо из целого числа; либо из необязательного '+' или ' ', за которым следует необязательное число, за которым следует необязательный 'E' или 'F'.

Если в начале s стоит '+', положительные значения возвращаются с ведущим '+'.

Пробел в начале s возвращает положительные значения с ведущим пробелом.

Если s содержит число, пробел вставляется после каждой группы из такого количества дробных цифр.

Если s заканчивается на 'E', используется инжиниринговая нотация (0.xxxxEnn).

Если s заканчивается на 'F', используется стандартный формат с плавающей точкой.

Примеры:

BigDecimal('-123.45678901234567890').to_s('5F')
  #=> '-123.45678 90123 45678 9'

BigDecimal('123.45678901234567890').to_s('+8F')
  #=> '+123.45678901 23456789'

BigDecimal('123.45678901234567890').to_s(' F')
  #=> ' 123.4567890123456789'
truncate(n) Показать исходный код
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);
}

Округляет до ближайшего целого числа (по умолчанию) и возвращает результат как 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
zero?() Показать исходный код
static VALUE
BigDecimal_zero(VALUE self)
{
    Real *a = GetVpValue(self, 1);
    return VpIsZero(a) ? Qtrue : Qfalse;
}

Возвращает True, если значение равно нулю.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API