Spec-Zone.ru › Ruby 2.5

класс BigDecimal

Родитель:
Numeric

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

Введение

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

Например:

42**13  #=>   1265437718438866624512

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

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

Например, попробуйте:

sum = 0
10_000.times do
  sum = sum + 0.0001
end
print sum #=> 0.9999999999999062

и сравните с результатом от:

require 'bigdecimal'

sum = BigDecimal("0")
10_000.times do
  sum = sum + BigDecimal("0.0001")
end
print sum #=> 0.1E1

Аналогично:

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

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

Особенности точной десятичной арифметики

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

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

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

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

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

Не число

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

Пример:

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

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

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

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

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

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

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

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

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

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

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

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

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

bigdecimal/util

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

require 'bigdecimal/util'

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

Лицензия

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

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

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

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

Константы

BASE

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

EXCEPTION_ALL

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

EXCEPTION_INFINITY

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

EXCEPTION_NaN

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

EXCEPTION_OVERFLOW

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

EXCEPTION_UNDERFLOW

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

EXCEPTION_ZERODIVIDE

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

INFINITY

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

NAN

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

ROUND_CEILING

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

ROUND_DOWN

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

ROUND_FLOOR

Округление к -Бесконечности. См. ::mode.

ROUND_HALF_DOWN

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

ROUND_HALF_EVEN

Округление к четному соседу. См. ::mode.

ROUND_HALF_UP

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

ROUND_MODE

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

ROUND_UP

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

SIGN_NEGATIVE_FINITE

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

SIGN_NEGATIVE_INFINITE

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

SIGN_NEGATIVE_ZERO

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

SIGN_NaN

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

SIGN_POSITIVE_FINITE

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

SIGN_POSITIVE_INFINITE

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

SIGN_POSITIVE_ZERO

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

VERSION

Версия библиотеки bigdecimal

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

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

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

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

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

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

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

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

Метод для поддержки маршалинга JSON.

limit(digits) Показать исходный код
static VALUE
BigDecimal_limit(int argc, VALUE *argv, VALUE self)
{
    VALUE  nFig;
    VALUE  nCur = INT2NUM(VpGetPrecLimit());

    if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
        int nf;
        if (NIL_P(nFig)) return nCur;
        nf = NUM2INT(nFig);
        if (nf < 0) {
            rb_raise(rb_eArgError, "argument must be positive");
        }
        VpSetPrecLimit(nf);
    }
    return nCur;
}

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

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

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

mode(mode, value) Показать исходный код
static VALUE
BigDecimal_mode(int argc, VALUE *argv, VALUE self)
{
    VALUE which;
    VALUE val;
    unsigned long f,fo;

    rb_scan_args(argc, argv, "11", &which, &val);
    f = (unsigned long)NUM2INT(which);

    if (f & VP_EXCEPTION_ALL) {
        /* Exception mode setting */
        fo = VpGetException();
        if (val == Qnil) return INT2FIX(fo);
        if (val != Qfalse && val!=Qtrue) {
            rb_raise(rb_eArgError, "second argument must be true or false");
            return Qnil; /* Not reached */
        }
        if (f & VP_EXCEPTION_INFINITY) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) :
                        (fo & (~VP_EXCEPTION_INFINITY))));
        }
        fo = VpGetException();
        if (f & VP_EXCEPTION_NaN) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) :
                        (fo & (~VP_EXCEPTION_NaN))));
        }
        fo = VpGetException();
        if (f & VP_EXCEPTION_UNDERFLOW) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) :
                        (fo & (~VP_EXCEPTION_UNDERFLOW))));
        }
        fo = VpGetException();
        if(f & VP_EXCEPTION_ZERODIVIDE) {
            VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) :
                        (fo & (~VP_EXCEPTION_ZERODIVIDE))));
        }
        fo = VpGetException();
        return INT2FIX(fo);
    }
    if (VP_ROUND_MODE == f) {
        /* Rounding mode setting */
        unsigned short sw;
        fo = VpGetRoundMode();
        if (NIL_P(val)) return INT2FIX(fo);
        sw = check_rounding_mode(val);
        fo = VpSetRoundMode(sw);
        return INT2FIX(fo);
    }
    rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid");
    return Qnil;
}

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

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

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

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

EXCEPTION_NaN

NaN

EXCEPTION_INFINITY

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

EXCEPTION_UNDERFLOW

0

EXCEPTION_OVERFLOW

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

EXCEPTION_ZERODIVIDE

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

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

ROUND_UP, :up

округление от нуля

ROUND_DOWN, :down, :truncate

округление к нулю (обрезание)

ROUND_HALF_UP, :half_up, :default

округление к ближайшему соседу, если оба соседа равноудалены, в этом случае округлять от нуля. (по умолчанию)

ROUND_HALF_DOWN, :half_down

округление к ближайшему соседу, если оба соседа равноудалены, в этом случае округлять к нулю.

ROUND_HALF_EVEN, :half_even, :banker

округление к ближайшему соседу, если оба соседа равноудалены, в этом случае округлять к ближайшему четному соседу (округление по банкерской схеме)

ROUND_CEILING, :ceiling, :ceil

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

ROUND_FLOOR, :floor

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

new(initial, digits) Показать исходный код
static VALUE
BigDecimal_s_new(int argc, VALUE *argv, VALUE self)
{
  rb_warning("BigDecimal.new is deprecated; use Kernel.BigDecimal method instead.");
  return rb_call_super(argc, argv);
}

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

initial

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

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

digits

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

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

Исключения

TypeError

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

TypeError

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

ArgumentError

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

ArgumentError

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

save_exception_mode { ... } Показать исходный код
static VALUE
BigDecimal_save_exception_mode(VALUE self)
{
    unsigned short const exception_mode = VpGetException();
    int state;
    VALUE ret = rb_protect(rb_yield, Qnil, &state);
    VpSetException(exception_mode);
    if (state) rb_jump_tag(state);
    return ret;
}

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

BigDecimal.save_exception_mode do
  BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
  BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)

  BigDecimal(BigDecimal('Infinity'))
  BigDecimal(BigDecimal('-Infinity'))
  BigDecimal(BigDecimal('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
   */
#ifndef RUBY_BIGDECIMAL_VERSION
# error RUBY_BIGDECIMAL_VERSION is not defined
#endif
  rb_warning("BigDecimal.ver is deprecated; use BigDecimal::VERSION instead.");
  return rb_str_new2(RUBY_BIGDECIMAL_VERSION);
}

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

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

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

+BigDecimal('5')  #=> 0.5e1
a - b → bigdecimal Показать исходный код
static VALUE
BigDecimal_sub(VALUE self, VALUE r)
{
    ENTER(5);
    Real *c, *a, *b;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self,1));
    if (RB_TYPE_P(r, T_FLOAT)) {
        b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
    }
    else if (RB_TYPE_P(r, T_RATIONAL)) {
        b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
    }
    else {
        b = GetVpValue(r,0);
    }

    if (!b) return DoSomeOne(self,r,'-');
    SAVE(b);

    if (VpIsNaN(b)) return b->obj;
    if (VpIsNaN(a)) return a->obj;

    mx = GetAddSubPrec(a,b);
    if (mx == (size_t)-1L) {
        GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
        VpAddSub(c, a, b, -1);
    }
    else {
        GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
        if (!mx) {
            VpSetInf(c,VpGetSign(a));
        }
        else {
            VpAddSub(c, a, b, -1);
        }
    }
    return ToValue(c);
}

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

Например:

c = a - b

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

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

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

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

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

-BigDecimal('5')  #=> -0.5e1
a / b → bigdecimal Показать исходный код
static VALUE
BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{
    ENTER(5);
    Real *c=NULL, *res=NULL, *div = NULL;
    r = BigDecimal_divide(&c, &res, &div, self, r);
    if (!NIL_P(r)) return r; /* coerced by other */
    SAVE(c); SAVE(res); SAVE(div);
    /* a/b = c + r/b */
    /* c xxxxx
       r 00000yyyyy  ==> (y/b)*BASE >= HALF_BASE
     */
    /* Round */
    if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
        VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
    }
    return ToValue(c);
}

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

См. #div.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Значения могут быть приведены к типу для выполнения сравнения (см. ==, #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('Infinity')
  #=> Infinity
BigDecimal._load(inf._dump)
  #=> Infinity

См. модуль Marshal.

abs → big_decimal Показать исходный код
static VALUE
BigDecimal_abs(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

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

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

BigDecimal('5').abs  #=> 0.5e1
BigDecimal('-3').abs #=> 0.3e1
add(value, digits) Показать исходный код
static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{
    ENTER(2);
    Real *cv;
    SIGNED_VALUE mx = GetPrecisionInt(n);
    if (mx == 0) return BigDecimal_add(self, b);
    else {
        size_t pl = VpSetPrecLimit(0);
        VALUE   c = BigDecimal_add(self, b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv, GetVpValue(c, 1));
        VpLeftRound(cv, VpGetRoundMode(), mx);
        return ToValue(cv);
    }
}
+

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

Например:

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

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

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

Сериализуйте объект в JSON с помощью Marshal.

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

ceil(n) Показать исходный код
static VALUE
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
        iLoc = 0;
    } else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
    if (argc == 0) {
        return BigDecimal_to_i(ToValue(c));
    }
    return ToValue(c);
}

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

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

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

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

BigDecimal('3.14159').ceil(3) #=> 3.142
BigDecimal('13345.234').ceil(-2) #=> 13400.0
clone() Показать исходный код
static VALUE
BigDecimal_clone(VALUE self)
{
  return self;
}
coerce(p1) Показать исходный код
static VALUE
BigDecimal_coerce(VALUE self, VALUE other)
{
    ENTER(2);
    VALUE obj;
    Real *b;

    if (RB_TYPE_P(other, T_FLOAT)) {
        GUARD_OBJ(b, GetVpValueWithPrec(other, DBL_DIG+1, 1));
        obj = rb_assoc_new(ToValue(b), self);
    }
    else {
        if (RB_TYPE_P(other, T_RATIONAL)) {
            Real* pv = DATA_PTR(self);
            GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
        }
        else {
            GUARD_OBJ(b, GetVpValue(other, 1));
        }
        obj = rb_assoc_new(b->obj, self);
    }

    return obj;
}

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

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

Например:

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

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

END_OF_DOCUMENT_MARKER
div(value, digits) → bigdecimal or integer Показать исходный код
static VALUE
BigDecimal_div3(int argc, VALUE *argv, VALUE self)
{
    VALUE b,n;

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

    return BigDecimal_div2(self, b, n);
}

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

digits

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

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

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

Примеры:

a = BigDecimal("4")
b = BigDecimal("3")

a.div(b, 3)  # => 0.133e1

a.div(b, 0)  # => 0.1333333333333333333e1
a / b        # => 0.1333333333333333333e1
a.quo(b)     # => 0.1333333333333333333e1

a.div(b)     # => 1
divmod(value) Показать исходный код
static VALUE
BigDecimal_divmod(VALUE self, VALUE r)
{
    ENTER(5);
    Real *div = NULL, *mod = NULL;

    if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
        SAVE(div); SAVE(mod);
        return rb_assoc_new(ToValue(div), ToValue(mod));
    }
    return DoSomeOne(self,r,rb_intern("divmod"));
}

Делит на указанное значение и возвращает частное и остаток как числа BigDecimal. Частное округляется к отрицательной бесконечности.

Например:

require 'bigdecimal'

a = BigDecimal("42")
b = BigDecimal("9")

q, m = a.divmod(b)

c = q * b + m

a == c  #=> true

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

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

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

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

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

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

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

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

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

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

fix() Показать исходный код
static VALUE
BigDecimal_fix(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec *(VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
    return ToValue(c);
}

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

floor(n) Показать исходный код
static VALUE
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
        iLoc = 0;
    }
    else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
#ifdef BIGDECIMAL_DEBUG
    VPrint(stderr, "floor: c=%\n", c);
#endif
    if (argc == 0) {
        return BigDecimal_to_i(ToValue(c));
    }
    return ToValue(c);
}

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

BigDecimal('3.14159').floor #=> 3
BigDecimal('-9.1').floor #=> -10

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

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

BigDecimal('3.14159').floor(3) #=> 3.141
BigDecimal('13345.234').floor(-2) #=> 13300.0
frac() Показать исходный код
static VALUE
BigDecimal_frac(VALUE self)
{
    ENTER(5);
    Real *c, *a;
    size_t mx;

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

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

hash Показать исходный код
static VALUE
BigDecimal_hash(VALUE self)
{
    ENTER(1);
    Real *p;
    st_index_t hash;

    GUARD_OBJ(p, GetVpValue(self, 1));
    hash = (st_index_t)p->sign;
    /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
    if(hash == 2 || hash == (st_index_t)-2) {
        hash ^= rb_memhash(p->frac, sizeof(BDIGIT)*p->Prec);
        hash += p->exponent;
    }
    return ST2FIX(hash);
}

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

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

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

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

inspect() Показать исходный код
static VALUE
BigDecimal_inspect(VALUE self)
{
    ENTER(5);
    Real *vp;
    volatile VALUE str;
    size_t nc;

    GUARD_OBJ(vp, GetVpValue(self, 1));
    nc = VpNumOfChars(vp, "E");

    str = rb_str_new(0, nc);
    VpToString(vp, RSTRING_PTR(str), 0, 0);
    rb_str_resize(str, strlen(RSTRING_PTR(str)));
    return str;
}

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

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

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

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

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

См. #divmod.

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

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

Например:

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

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

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

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

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

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

power(n) Показать исходный код
power(n, prec)
static VALUE
BigDecimal_power(int argc, VALUE*argv, VALUE self)
{
    ENTER(5);
    VALUE vexp, prec;
    Real* exp = NULL;
    Real *x, *y;
    ssize_t mp, ma, n;
    SIGNED_VALUE int_exp;
    double d;

    rb_scan_args(argc, argv, "11", &vexp, &prec);

    GUARD_OBJ(x, GetVpValue(self, 1));
    n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);

    if (VpIsNaN(x)) {
        y = VpCreateRbObject(n, "0#");
        RB_GC_GUARD(y->obj);
        VpSetNaN(y);
        return ToValue(y);
    }

  retry:
    switch (TYPE(vexp)) {
      case T_FIXNUM:
        break;

      case T_BIGNUM:
        break;

      case T_FLOAT:
        d = RFLOAT_VALUE(vexp);
        if (d == round(d)) {
            if (FIXABLE(d)) {
                vexp = LONG2FIX((long)d);
            }
            else {
                vexp = rb_dbl2big(d);
            }
            goto retry;
        }
        exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1);
        break;

      case T_RATIONAL:
        if (is_zero(rb_rational_num(vexp))) {
            if (is_positive(vexp)) {
                vexp = INT2FIX(0);
                goto retry;
            }
        }
        else if (is_one(rb_rational_den(vexp))) {
            vexp = rb_rational_num(vexp);
            goto retry;
        }
        exp = GetVpValueWithPrec(vexp, n, 1);
        break;

      case T_DATA:
        if (is_kind_of_BigDecimal(vexp)) {
            VALUE zero = INT2FIX(0);
            VALUE rounded = BigDecimal_round(1, &zero, vexp);
            if (RTEST(BigDecimal_eq(vexp, rounded))) {
                vexp = BigDecimal_to_i(vexp);
                goto retry;
            }
            exp = DATA_PTR(vexp);
            break;
        }
        /* fall through */
      default:
        rb_raise(rb_eTypeError,
                 "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
                 RB_OBJ_CLASSNAME(vexp));
    }

    if (VpIsZero(x)) {
        if (is_negative(vexp)) {
            y = VpCreateRbObject(n, "#0");
            RB_GC_GUARD(y->obj);
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        /* (-0) ** (-even_integer)  -> Infinity */
                        VpSetPosInf(y);
                    }
                    else {
                        /* (-0) ** (-odd_integer)  -> -Infinity */
                        VpSetNegInf(y);
                    }
                }
                else {
                    /* (-0) ** (-non_integer)  -> Infinity */
                    VpSetPosInf(y);
                }
            }
            else {
                /* (+0) ** (-num)  -> Infinity */
                VpSetPosInf(y);
            }
            return ToValue(y);
        }
        else if (is_zero(vexp)) {
            return ToValue(VpCreateRbObject(n, "1"));
        }
        else {
            return ToValue(VpCreateRbObject(n, "0"));
        }
    }

    if (is_zero(vexp)) {
        return ToValue(VpCreateRbObject(n, "1"));
    }
    else if (is_one(vexp)) {
        return self;
    }

    if (VpIsInf(x)) {
        if (is_negative(vexp)) {
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        /* (-Infinity) ** (-even_integer) -> +0 */
                        return ToValue(VpCreateRbObject(n, "0"));
                    }
                    else {
                        /* (-Infinity) ** (-odd_integer) -> -0 */
                        return ToValue(VpCreateRbObject(n, "-0"));
                    }
                }
                else {
                    /* (-Infinity) ** (-non_integer) -> -0 */
                    return ToValue(VpCreateRbObject(n, "-0"));
                }
            }
            else {
                return ToValue(VpCreateRbObject(n, "0"));
            }
        }
        else {
            y = VpCreateRbObject(n, "0#");
            if (BIGDECIMAL_NEGATIVE_P(x)) {
                if (is_integer(vexp)) {
                    if (is_even(vexp)) {
                        VpSetPosInf(y);
                    }
                    else {
                        VpSetNegInf(y);
                    }
                }
                else {
                    /* TODO: support complex */
                    rb_raise(rb_eMathDomainError,
                             "a non-integral exponent for a negative base");
                }
            }
            else {
                VpSetPosInf(y);
            }
            return ToValue(y);
        }
    }

    if (exp != NULL) {
        return rmpd_power_by_big_decimal(x, exp, n);
    }
    else if (RB_TYPE_P(vexp, T_BIGNUM)) {
        VALUE abs_value = BigDecimal_abs(self);
        if (is_one(abs_value)) {
            return ToValue(VpCreateRbObject(n, "1"));
        }
        else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
            if (is_negative(vexp)) {
                y = VpCreateRbObject(n, "0#");
                if (is_even(vexp)) {
                    VpSetInf(y, VpGetSign(x));
                }
                else {
                    VpSetInf(y, -VpGetSign(x));
                }
                return ToValue(y);
            }
            else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
                return ToValue(VpCreateRbObject(n, "-0"));
            }
            else {
                return ToValue(VpCreateRbObject(n, "0"));
            }
        }
        else {
            if (is_positive(vexp)) {
                y = VpCreateRbObject(n, "0#");
                if (is_even(vexp)) {
                    VpSetInf(y, VpGetSign(x));
                }
                else {
                    VpSetInf(y, -VpGetSign(x));
                }
                return ToValue(y);
            }
            else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
                return ToValue(VpCreateRbObject(n, "-0"));
            }
            else {
                return ToValue(VpCreateRbObject(n, "0"));
            }
        }
    }

    int_exp = FIX2LONG(vexp);
    ma = int_exp;
    if (ma <  0) ma = -ma;
    if (ma == 0) ma = 1;

    if (VpIsDef(x)) {
        mp = x->Prec * (VpBaseFig() + 1);
        GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
    }
    else {
        GUARD_OBJ(y, VpCreateRbObject(1, "0"));
    }
    VpPower(y, x, int_exp);
    if (!NIL_P(prec) && VpIsDef(y)) {
        VpMidRound(y, VpGetRoundMode(), n);
    }
    return ToValue(y);
}

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

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

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

precs → array Показать исходный код
static VALUE
BigDecimal_prec(VALUE self)
{
    ENTER(1);
    Real *p;
    VALUE obj;

    GUARD_OBJ(p, GetVpValue(self, 1));
    obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
                       INT2NUM(p->MaxPrec*VpBaseFig()));
    return obj;
}

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

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

BigDecimal('5').precs #=> [9, 18]
quo(value) → bigdecimal Показать исходный код
static VALUE
BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{
    ENTER(5);
    Real *c=NULL, *res=NULL, *div = NULL;
    r = BigDecimal_divide(&c, &res, &div, self, r);
    if (!NIL_P(r)) return r; /* coerced by other */
    SAVE(c); SAVE(res); SAVE(div);
    /* a/b = c + r/b */
    /* c xxxxx
       r 00000yyyyy  ==> (y/b)*BASE >= HALF_BASE
     */
    /* Round */
    if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
        VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
    }
    return ToValue(c);
}

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

См. #div.

remainder(value) Показать исходный код
static VALUE
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
{
    VALUE  f;
    Real  *d, *rv = 0;
    f = BigDecimal_divremain(self, r, &d, &rv);
    if (!NIL_P(f)) return f;
    return ToValue(rv);
}

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

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

round(n, mode) Показать исходный код
static VALUE
BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real   *c, *a;
    int    iLoc = 0;
    VALUE  vLoc;
    VALUE  vRound;
    size_t mx, pl;

    unsigned short sw = VpGetRoundMode();

    switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
      case 0:
        iLoc = 0;
        break;
      case 1:
        if (RB_TYPE_P(vLoc, T_HASH)) {
            sw = check_rounding_mode_option(vLoc);
        }
        else {
            iLoc = NUM2INT(vLoc);
        }
        break;
      case 2:
        iLoc = NUM2INT(vLoc);
        if (RB_TYPE_P(vRound, T_HASH)) {
            sw = check_rounding_mode_option(vRound);
        }
        else {
            sw = check_rounding_mode(vRound);
        }
        break;
      default:
        break;
    }

    pl = VpSetPrecLimit(0);
    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, sw, iLoc);
    if (argc == 0) {
        return BigDecimal_to_i(ToValue(c));
    }
    return ToValue(c);
}

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

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

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

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

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

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

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

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

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

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

BigDecimal::SIGN_NaN

значение является числом Not a Number

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 является числом Not a Number.

Второе значение — это строка, представляющая значащие цифры BigDecimal без ведущих нулей.

Третье значение — основание, используемое для арифметики (в настоящее время всегда 10), как Целое число.

Четвёртое значение — Целое число — показатель степени.

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

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

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

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

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

Например:

c = a.sub(b,n)
digits

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

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

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

require 'bigdecimal/util'

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

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

require 'bigdecimal/util'

d = BigDecimal("3.14")
d.to_digits                  # => "3.14"
to_f() Показать исходный код
static VALUE
BigDecimal_to_f(VALUE self)
{
    ENTER(1);
    Real *p;
    double d;
    SIGNED_VALUE e;
    char *buf;
    volatile VALUE str;

    GUARD_OBJ(p, GetVpValue(self, 1));
    if (VpVtoD(&d, &e, p) != 1)
        return rb_float_new(d);
    if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
        goto overflow;
    if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
        goto underflow;

    str = rb_str_new(0, VpNumOfChars(p, "E"));
    buf = RSTRING_PTR(str);
    VpToString(p, buf, 0, 0);
    errno = 0;
    d = strtod(buf, 0);
    if (errno == ERANGE) {
        if (d == 0.0) goto underflow;
        if (fabs(d) >= HUGE_VAL) goto overflow;
    }
    return rb_float_new(d);

overflow:
    VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
    if (BIGDECIMAL_NEGATIVE_P(p))
        return rb_float_new(VpGetDoubleNegInf());
    else
        return rb_float_new(VpGetDoublePosInf());

underflow:
    VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
    if (BIGDECIMAL_NEGATIVE_P(p))
        return rb_float_new(-0.0);
    else
        return rb_float_new(0.0);
}

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

to_i() Показать исходный код
static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    ssize_t e, nf;
    Real *p;

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

    e = VpExponent10(p);
    if (e <= 0) return INT2FIX(0);
    nf = VpBaseFig();
    if (e <= nf) {
        return LONG2NUM((long)(VpGetSign(p) * (BDIGIT_DBL_SIGNED)p->frac[0]));
    }
    else {
        VALUE a = BigDecimal_split(self);
        VALUE digits = RARRAY_AREF(a, 1);
        VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
        VALUE ret;
        ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);

        if (BIGDECIMAL_NEGATIVE_P(p)) {
            numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
        }
        if (dpower < 0) {
            ret = rb_funcall(numerator, rb_intern("div"), 1,
                              rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                         INT2FIX(-dpower)));
        }
        else {
            ret = rb_funcall(numerator, '*', 1,
                             rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                        INT2FIX(dpower)));
        }
        if (RB_TYPE_P(ret, T_FLOAT)) {
            rb_raise(rb_eFloatDomainError, "Infinity");
        }
        return ret;
    }
}

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

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

to_int() Показать исходный код
static VALUE
BigDecimal_to_i(VALUE self)
{
    ENTER(5);
    ssize_t e, nf;
    Real *p;

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

    e = VpExponent10(p);
    if (e <= 0) return INT2FIX(0);
    nf = VpBaseFig();
    if (e <= nf) {
        return LONG2NUM((long)(VpGetSign(p) * (BDIGIT_DBL_SIGNED)p->frac[0]));
    }
    else {
        VALUE a = BigDecimal_split(self);
        VALUE digits = RARRAY_AREF(a, 1);
        VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
        VALUE ret;
        ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);

        if (BIGDECIMAL_NEGATIVE_P(p)) {
            numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
        }
        if (dpower < 0) {
            ret = rb_funcall(numerator, rb_intern("div"), 1,
                              rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                         INT2FIX(-dpower)));
        }
        else {
            ret = rb_funcall(numerator, '*', 1,
                             rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                        INT2FIX(dpower)));
        }
        if (RB_TYPE_P(ret, T_FLOAT)) {
            rb_raise(rb_eFloatDomainError, "Infinity");
        }
        return ret;
    }
}

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

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

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

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

to_r() Показать исходный код
static VALUE
BigDecimal_to_r(VALUE self)
{
    Real *p;
    ssize_t sign, power, denomi_power;
    VALUE a, digits, numerator;

    p = GetVpValue(self, 1);
    BigDecimal_check_num(p);

    sign = VpGetSign(p);
    power = VpExponent10(p);
    a = BigDecimal_split(self);
    digits = RARRAY_AREF(a, 1);
    denomi_power = power - RSTRING_LEN(digits);
    numerator = rb_funcall(digits, rb_intern("to_i"), 0);

    if (sign < 0) {
        numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
    }
    if (denomi_power < 0) {
        return rb_Rational(numerator,
                           rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                      INT2FIX(-denomi_power)));
    }
    else {
        return rb_Rational1(rb_funcall(numerator, '*', 1,
                                       rb_funcall(INT2FIX(10), rb_intern("**"), 1,
                                                  INT2FIX(denomi_power))));
    }
}

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

to_s(s) Показать исходный код
static VALUE
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    int   fmt = 0;   /* 0: E format, 1: F format */
    int   fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
    Real  *vp;
    volatile VALUE str;
    char  *psz;
    char   ch;
    size_t nc, mc = 0;
    SIGNED_VALUE m;
    VALUE  f;

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

    if (rb_scan_args(argc, argv, "01", &f) == 1) {
        if (RB_TYPE_P(f, T_STRING)) {
            psz = StringValueCStr(f);
            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 {
            m = NUM2INT(f);
            if (m <= 0) {
                rb_raise(rb_eArgError, "argument must be positive");
            }
            mc = (size_t)m;
        }
    }
    if (fmt) {
        nc = VpNumOfChars(vp, "F");
    }
    else {
        nc = VpNumOfChars(vp, "E");
    }
    if (mc > 0) {
        nc += (nc + mc - 1) / mc + 1;
    }

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

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

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

По умолчанию формат выглядит как 0.xxxxEnn.

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

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

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

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

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

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

Примеры:

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

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

BigDecimal('123.45678901234567890').to_s(' F')
  #=> ' 123.4567890123456789'
truncate(n) Показать исходный код
static VALUE
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
{
    ENTER(5);
    Real *c, *a;
    int iLoc;
    VALUE vLoc;
    size_t mx, pl = VpSetPrecLimit(0);

    if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
        iLoc = 0;
    }
    else {
        iLoc = NUM2INT(vLoc);
    }

    GUARD_OBJ(a, GetVpValue(self, 1));
    mx = a->Prec * (VpBaseFig() + 1);
    GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
    VpSetPrecLimit(pl);
    VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
    if (argc == 0) {
        return BigDecimal_to_i(ToValue(c));
    }
    return ToValue(c);
}

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

BigDecimal('3.14159').truncate #=> 3
BigDecimal('8.7').truncate #=> 8
BigDecimal('-9.9').truncate #=> -9

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

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

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