Spec-Zone.ru › Ruby 2.3

класс 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 считаются одинаковыми для целей сравнения.

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

Лицензия

Авторское право (C) 2002 Шигео Кобаяси <shigeo@tinyforest.gr.jp>.

BigDecimal распространяется под лицензиями Ruby и 2-х пунктов BSD. Подробности см. в LICENSE.txt.

Поддерживается mrkn <mrkn@mrkn.jp> и участниками ruby-core.

Документировано zzak <zachary@zacharyscott.net>, mathew <meta@pobox.com> и многими другими участниками.

BigDecimal расширяет базовый класс Numeric, предоставляя методы to_digits и to_d.

Когда вы используете BigDecimal в своём приложении, этот метод будет доступен для объектов BigDecimal.

Константы

BASE

Базовое значение, используемое во внутренних расчётах. В 32-битной системе BASE равно 10000, что указывает на то, что вычисления выполняются группами по 4 цифры. (Если бы оно было больше, BASE**2 не поместилось бы в 32 бита, поэтому нельзя было бы гарантировать, что две группы всегда можно умножить друг на друга без переполнения.)

EXCEPTION_ALL

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

EXCEPTION_INFINITY

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

EXCEPTION_NaN

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

EXCEPTION_OVERFLOW

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

EXCEPTION_UNDERFLOW

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

EXCEPTION_ZERODIVIDE

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

INFINITY

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

NAN

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

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.

END_OF_DOCUMENT_MARKER

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

_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.

Метод для поддержки маршаллирования 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;
        Check_Type(nFig, T_FIXNUM);
        nf = FIX2INT(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);
    Check_Type(which, T_FIXNUM);
    f = (unsigned long)FIX2INT(which);

    if (f & VP_EXCEPTION_ALL) {
        /* Exception mode setting */
        fo = VpGetException();
        if (val == Qnil) return INT2FIX(fo);
        if (val != Qfalse && val!=Qtrue) {
            rb_raise(rb_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

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

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

digits

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

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

Исключения

TypeError

Если тип initial не является ни Fixnum, ни Bignum, ни Float, ни Rational, ни BigDecimal, это исключение генерируется.

TypeError

Если digits не является Fixnum, это исключение генерируется.

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) 

Возвращает остаток от деления на 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.

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

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

Например:

b = +a  # b == a
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.

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

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

Например:

b = -a
b == a * -1
div(value, digits) Показать исходный код
quo(value)
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);
}

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

Например:

c = a.div(b,n)
digits

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

Если digits равно 0, результат совпадает с оператором /. В противном случае, результат — целочисленный BigDecimal, аналогично Numeric#div.

Псевдоним quo предоставлен, поскольку div(value, 0) эквивалентен вычислению частного; см. #divmod.

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')
  #=> #<BigDecimal:1e16fa8,'Infinity',9(9)>
BigDecimal._load(inf._dump)
  #=> #<BigDecimal:1df8dc8,'Infinity',9(9)>

См. модуль Marshal.

abs() Показать исходный код
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 #=> 5
BigDecimal('-3').abs #=> 3
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 {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
    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
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.

div(p1, p2 = v2) Показать исходный код
static VALUE
BigDecimal_div3(int argc, VALUE *argv, VALUE self)
{
    VALUE b,n;

    rb_scan_args(argc, argv, "11", &b, &n);

    return BigDecimal_div2(self, b, n);
}
divmod(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 {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
#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 LONG2FIX((long)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 obj;
    size_t nc;
    char *psz, *tmp;

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

    obj = rb_str_new(0, nc+256);
    psz = RSTRING_PTR(obj);
    sprintf(psz, "#<BigDecimal:%"PRIxVALUE",'", self);
    tmp = psz + strlen(psz);
    VpToString(vp, tmp, 10, 0);
    tmp += strlen(tmp);
    sprintf(tmp, "',%"PRIuSIZE"(%"PRIuSIZE")>", VpPrec(vp)*VpBaseFig(), VpMaxPrec(vp)*VpBaseFig());
    rb_str_resize(obj, strlen(psz));
    return obj;
}

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

BigDecimal.new("1234.5678").inspect
  #=> "#<BigDecimal:b7ea1130,'0.12345678E4',8(12)>"

Первая часть — адрес, вторая — значение в виде строки, а последняя часть 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 (VpGetSign(x) < 0) {
                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 (VpGetSign(x) < 0) {
                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 (VpGetSign(x) < 0) {
                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 (VpGetSign(x) < 0 && 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 (VpGetSign(x) < 0 && 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 Показать исходный код
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.

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

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

Например:

c = a.div(b,n)
digits

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

Если digits равно 0, результат такой же, как у оператора /. В противном случае результат — целое число BigDecimal, аналогично Numeric#div.

Псевдоним quo предоставлен, так как div(value, 0) эквивалентно вычислению частного; см. #divmod.

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:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        break;
      case 2:
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
        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 в float следующим образом:

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 97
def to_d
  self
end

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

to_digits → string Показать исходный код
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 83
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'
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 (p->sign >= 0)
        return rb_float_new(VpGetDoublePosInf());
    else
        return rb_float_new(VpGetDoubleNegInf());

underflow:
    VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
    if (p->sign >= 0)
        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 (VpGetSign(p) < 0) {
            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;
    }
}

Возвращает значение как целое число (Fixnum или Bignum).

Если BigNumber — бесконечность или 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 (VpGetSign(p) < 0) {
            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;
    }
}

Возвращает значение как целое число (Fixnum или Bignum).

Если BigNumber — бесконечность или 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 {
        Check_Type(vLoc, T_FIXNUM);
        iLoc = FIX2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
    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