Spec-Zone.ru › Ruby 2.4

класс 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.new("0")
10_000.times do
  sum = sum + BigDecimal.new("0.0001")
end
print sum #=> 0.1E1

Аналогично:

(BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true

(1.2 - 1.0) == 0.2 #=> false

Особенности точных десятичных вычислений

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

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

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

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

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

Не число (NaN)

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

Пример:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Определяет, приведут ли переполнение, недополнение или деление на ноль к тому, что будет выброшено исключение. См. ::mode.

EXCEPTION_INFINITY

Определяет, что произойдёт, если результат вычисления равен бесконечности. См. ::mode.

EXCEPTION_NaN

Определяет, что произойдёт, если результат вычисления не является числом (NaN). См. ::mode.

EXCEPTION_OVERFLOW

Определяет, что произойдёт, если результат вычисления является переполнением (результат слишком велик для представления). См. ::mode.

EXCEPTION_UNDERFLOW

Определяет, что произойдёт, если результат вычисления является недополнением (результат слишком мал для представления). См. ::mode.

EXCEPTION_ZERODIVIDE

Определяет, что произойдёт, если выполняется деление на ноль. См. ::mode.

INFINITY

Значение положительной бесконечности.

NAN

Значение «не число».

ROUND_CEILING

Округление вверх до ближайшего большего или равного значения. См. ::mode.

ROUND_DOWN

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

ROUND_FLOOR

Округление вниз до ближайшего меньшего или равного значения. См. ::mode.

ROUND_HALF_DOWN

Указывает, что цифры ≥ 6 должны округляться вверх, а остальные – вниз. См. ::mode.

ROUND_HALF_EVEN

Округление к ближайшему чётному значению. См. ::mode.

ROUND_HALF_UP

Указывает, что цифры ≥ 5 должны округляться вверх, а остальные – вниз. См. ::mode.

ROUND_MODE

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

ROUND_UP

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

SIGN_NEGATIVE_FINITE

Указывает, что значение отрицательное и конечное. См. #sign.

SIGN_NEGATIVE_INFINITE

Указывает, что значение отрицательное и бесконечное. См. #sign.

SIGN_NEGATIVE_ZERO

Указывает, что значение равно -0. См. #sign.

SIGN_NaN

Указывает, что значение не является числом. См. #sign.

SIGN_POSITIVE_FINITE

Указывает, что значение положительное и конечное. См. #sign.

SIGN_POSITIVE_INFINITE

Указывает, что значение положительное и бесконечное. См. #sign.

SIGN_POSITIVE_ZERO

Указывает, что значение равно +0. См. #sign.

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

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

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

json_create(object) Показать исходный код
# File ext/json/lib/json/add/bigdecimal.rb, line 11
def self.json_create(object)
  BigDecimal._load object['b']
end

Импортировать объект JSON, маршализованный с помощью Marshal.

Метод для поддержки маршалинга 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 заданным значением. Округление выполняется при необходимости, как указано в методе ::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;
}

Управляет обработкой арифметических исключений и округления. Если значение не указано, возвращается текущее значение.

Шесть значений параметра mode управляют обработкой арифметических исключений:

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

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

EXCEPTION_NaN

NaN

EXCEPTION_INFINITY

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

EXCEPTION_UNDERFLOW

0

EXCEPTION_OVERFLOW

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

EXCEPTION_ZERODIVIDE

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

Одно значение параметра mode управляет округлением числовых значений: 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)

new(initial, digits) Показать исходный код
static VALUE
BigDecimal_initialize(int argc, VALUE *argv, VALUE self)
{
    ENTER(1);
    Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
    Real *x;

    GUARD_OBJ(x, BigDecimal_new(argc, argv));
    if (ToValue(x)) {
        pv = VpCopy(pv, x);
    }
    else {
        VpFree(pv);
        pv = x;
    }
    DATA_PTR(self) = pv;
    pv->obj = self;
    return self;
}

Создать новый объект BigDecimal.

initial

Начальное значение в виде целого числа (Integer), числа с плавающей точкой (Float), рационального числа (Rational), числа BigDecimal или строки.

Если это строка, пробелы игнорируются, а нераспознанные символы завершают значение.

digits

Количество значащих цифр в виде целого числа (Integer). Если опущено или равно 0, количество значащих цифр определяется из начального значения.

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

Исключения

TypeError

Если тип initial не является ни Integer, ни Float, ни Rational, ни BigDecimal, это исключение будет вызвано.

TypeError

Если digits не является целым числом (Integer), это исключение будет вызвано.

ArgumentError

Если initial является числом с плавающей точкой (Float), а digits больше, чем Float::DIG + 1, это исключение будет вызвано.

ArgumentError

Если initial является числом с плавающей точкой (Float) или рациональным числом (Rational), а значение digits опущено, это исключение будет вызвано.

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.new(BigDecimal('Infinity'))
  BigDecimal.new(BigDecimal('-Infinity'))
  BigDecimal(BigDecimal.new('NaN'))
end

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

См. ::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_*

См. ::mode

ver() Показать исходный код
static VALUE
BigDecimal_version(VALUE self)
{
    /*
     * 1.0.0: Ruby 1.8.0
     * 1.0.1: Ruby 1.8.1
     * 1.1.0: Ruby 1.9.3
    */
    return rb_str_new2("1.1.0");
}

Возвращает номер версии BigDecimal.

Публичные методы экземпляра

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

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

См. #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

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

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

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

См. #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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до указанного количества цифр в соответствии с ::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, точность результата зависит от точности внутреннего представления на платформе. Поэтому значение результата зависит от платформы.

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

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

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

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

См. #div.

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

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

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

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

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

Значения могут быть преобразованы для выполнения сравнения (см. ==, #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.new('1.0') == 1.0  #=> true
===(p1) Показать исходный код
static VALUE
BigDecimal_eq(VALUE self, VALUE r)
{
    return BigDecimalCmp(self, r, '=');
}

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

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

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

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

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

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

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

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

Значения могут быть преобразованы для выполнения сравнения (см. ==, #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;
}

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

inf = BigDecimal.new('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 = GetPositiveInt(n);
    if (mx == 0) return BigDecimal_add(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_add(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return ToValue(cv);
    }
}
+

Добавляет указанное значение.

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до указанного количества цифр в соответствии с ::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

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

BigDecimal('3.14159').ceil(3) #=> 3.142
BigDecimal('13345.234').ceil(-2) #=> 13400.0
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.new("1.0")
b = a / 2.0 #=> 0.5

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

END_OF_DOCUMENT_MARKER
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

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

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

Если digits не указано, результат — целое число, аналогично Numeric#div; см. также #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.new("42")
b = BigDecimal.new("9")

q, m = a.divmod(b)

c = q * b + m

a == c  #=> true

Целая часть q равна (a/b).floor, а остаток — это количество, которое необходимо добавить к q * b, чтобы получить a.

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

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

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

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

BigDecimal.new('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.

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

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

Возвращает отладочную информацию о значении в виде строки с разделителями запятых в угловых скобках с ведущим #:

BigDecimal.new("1234.5678").inspect
  #=> "0.12345678e4"

Первая часть — адрес, вторая — значение в виде строки, а последняя часть ss(mm) — соответственно текущее количество значащих цифр и максимальное количество значащих цифр.

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

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

См. #divmod.

mult(value, digits) Показать исходный код
static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = GetPositiveInt(n);
    if (mx == 0) return BigDecimal_mult(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_mult(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return ToValue(cv);
    }
}

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

Например:

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

Если указано и меньше, чем количество значащих цифр результата, результат округляется до этого количества цифр в соответствии с ::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);
}

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

См. #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.

BigDecimal('3.14159').round #=> 3
BigDecimal('8.7').round #=> 9
BigDecimal('-9.9').round #=> -10

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

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

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

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

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 = GetPositiveInt(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 = GetPositiveInt(n);
    if (mx == 0) return BigDecimal_sub(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_sub(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return ToValue(cv);
    }
}

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

Например:

c = a.sub(b,n)
digits

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

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

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

require 'bigdecimal/util'

d = BigDecimal.new("3.14")
d.to_d                       # => 0.314e1
to_digits → string Показать исходный код
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 88
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». Этот метод устарел; используйте #to_s(“F”) вместо него.

require 'bigdecimal/util'

d = BigDecimal.new("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. Применяются обычные ограничения точности и встроенные ошибки двоичной арифметики чисел с плавающей запятой Float.

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(*) Показать исходный код
# File ext/json/lib/json/add/bigdecimal.rb, line 26
def to_json(*)
  as_json.to_json
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 */
    int   fPlus = 0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
    Real  *vp;
    volatile VALUE str;
    char  *psz;
    char   ch;
    size_t nc, mc = 0;
    VALUE  f;

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

    if (rb_scan_args(argc, argv, "01", &f) == 1) {
        if (RB_TYPE_P(f, T_STRING)) {
            psz = StringValueCStr(f);
            rb_check_safe_obj(f);
            if (*psz == ' ') {
                fPlus = 1;
                psz++;
            }
            else if (*psz == '+') {
                fPlus = 2;
                psz++;
            }
            while ((ch = *psz++) != 0) {
                if (ISSPACE(ch)) {
                    continue;
                }
                if (!ISDIGIT(ch)) {
                    if (ch == 'F' || ch == 'f') {
                        fmt = 1; /* F format */
                    }
                    break;
                }
                mc = mc*10 + ch - '0';
            }
        }
        else {
            mc = (size_t)GetPositiveInt(f);
        }
    }
    if (fmt) {
        nc = VpNumOfChars(vp, "F");
    }
    else {
        nc = VpNumOfChars(vp, "E");
    }
    if (mc > 0) {
        nc += (nc + mc - 1) / mc + 1;
    }

    str = rb_str_new(0, nc);
    psz = RSTRING_PTR(str);

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

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

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

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

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

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

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

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

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

Примеры:

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

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

BigDecimal.new('123.45678901234567890').to_s(' F')
  #=> ' 123.4567890123456789'
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