Spec-Zone.ru › Ruby 2.2

класс BigDecimal

Родитель:
Numeric

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

Введение

Ruby предоставляет встроенную поддержку арифметики с произвольной точностью для целых чисел.

Например:

42**13  #=>   1265437718438866624512

BigDecimal предоставляет аналогичную поддержку для очень больших или очень точных чисел с плавающей точкой.

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

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

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

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

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

Не число

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

Пример:

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

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

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

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 Kobayashi <shigeo@tinyforest.gr.jp>.

Вы можете распространять под условиями либо GNU General Public License, либо Artistic License, как указано в файле README дистрибутива BigDecimal.

Поддерживается 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.

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

_load(p1) Показать исходный код
static VALUE
BigDecimal_load(VALUE self, VALUE str)
{
    ENTER(2);
    Real *pv;
    unsigned char *pch;
    unsigned char ch;
    unsigned long m=0;

    SafeStringValue(str);
    pch = (unsigned char *)RSTRING_PTR(str);
    /* First get max prec */
    while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
        if(!ISDIGIT(ch)) {
            rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
        }
        m = m*10 + (unsigned long)(ch-'0');
    }
    if (m > VpBaseFig()) m -= VpBaseFig();
    GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self));
    m /= VpBaseFig();
    if (m && pv->MaxPrec > m) {
        pv->MaxPrec = m+1;
    }
    return ToValue(pv);
}

Внутренний метод, используемый для поддержки маршалинга. См. модуль 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 10
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.

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

Это синоним #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;
}

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

Например:

b = +a  # b == a
value - digits → 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, точность результата зависит от точности внутреннего представления на платформе. Поэтому её значение зависит от платформы.

-@ Показать исходный код
static VALUE
BigDecimal_neg(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    GUARD_OBJ(a, GetVpValue(self, 1));
    GUARD_OBJ(c, VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
    VpAsgn(c, a, -1);
    return ToValue(c);
}

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

Например:

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('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 17
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 = ::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(p1) Показать исходный код
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 = ::new(“42”) b = ::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);
}

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

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

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

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 INT2FIX(hash);
}

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

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

infinite?() Показать исходный код
static VALUE
BigDecimal_IsInfinite(VALUE self)
{
    Real *p = GetVpValue(self, 1);
    if (VpIsPosInf(p)) return INT2FIX(1);
    if (VpIsNegInf(p)) return INT2FIX(-1);
    return Qnil;
}

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

inspect() Показать исходный код
static VALUE
BigDecimal_inspect(VALUE self)
{
    ENTER(5);
    Real *vp;
    volatile VALUE 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;
}

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

::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, если значение — не число

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

Округляет до ближайшего 1 (по умолчанию), возвращая результат как BigDecimal.

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

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

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

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

sub(value, digits) -> bigdecimal

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

Например:

c = a.sub(b,n)
digits

Если указано и меньше, чем количество значащих цифр результата,

результат округляется до этого количества цифр в соответствии с ::mode.

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

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

to_digits → string Показать исходный код
# File ext/bigdecimal/lib/bigdecimal/util.rb, line 82
def to_digits
  if self.nan? || self.infinite? || self.zero?
    self.to_s
  else
    i       = self.to_i.to_s
    _,f,_,z = self.frac.split
    i + "." + ("0"*(-z)) + f
  end
end

Преобразует 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_PTR(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_PTR(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 25
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_PTR(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)) {
            SafeStringValue(f);
            psz = RSTRING_PTR(f);
            if (*psz == ' ') {
                fPlus = 1;
                psz++;
            }
            else if (*psz == '+') {
                fPlus = 2;
                psz++;
            }
            while ((ch = *psz++) != 0) {
                if (ISSPACE(ch)) {
                    continue;
                }
                if (!ISDIGIT(ch)) {
                    if (ch == 'F' || ch == 'f') {
                        fmt = 1; /* F format */
                    }
                    break;
                }
                mc = mc*10 + ch - '0';
            }
        }
        else {
            mc = (size_t)GetPositiveInt(f);
        }
    }
    if (fmt) {
        nc = VpNumOfChars(vp, "F");
    }
    else {
        nc = VpNumOfChars(vp, "E");
    }
    if (mc > 0) {
        nc += (nc + mc - 1) / mc + 1;
    }

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

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

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

Формат по умолчанию выглядит как 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

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

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

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