Spec-Zone.ru › Ruby 2.7

класс Numeric

Родитель:
Объект
Включенные модули:
Comparable

Numeric — это класс, от которого должны наследоваться все числовые классы более высокого уровня.

Numeric позволяет создать объекты, выделенные в куче. Другие основные числовые классы, такие как Integer, реализованы как непосредственные, что означает, что каждый Integer является одним неизменяемым объектом, который всегда передаётся по значению.

a = 1
1.object_id == a.object_id   #=> true

Может быть только один экземпляр целого числа 1, например. Ruby гарантирует это, предотвращая создание экземпляров. Если попытка дублирования всё же происходит, возвращается тот же экземпляр.

Integer.new(1)                   #=> NoMethodError: undefined method `new' for Integer:Class
1.dup                            #=> 1
1.object_id == 1.dup.object_id   #=> true

По этой причине Numeric следует использовать при определении других числовых классов.

Классы, которые наследуют от Numeric, должны реализовывать coerce, который возвращает двумерный Array, содержащий объект, который был преобразован в экземпляр нового класса, и self (см. coerce).

Наследуемые классы также должны реализовать методы арифметических операторов (+, -, * и /) и оператор <=> (см. Comparable). Эти методы могут полагаться на coerce для обеспечения межработоспособности с экземплярами других числовых классов.

class Tally < Numeric
  def initialize(string)
    @string = string
  end

  def to_s
    @string
  end

  def to_i
    @string.size
  end

  def coerce(other)
    [self.class.new('|' * other.to_i), self]
  end

  def <=>(other)
    to_i <=> other.to_i
  end

  def +(other)
    self.class.new('|' * (to_i + other.to_i))
  end

  def -(other)
    self.class.new('|' * (to_i - other.to_i))
  end

  def *(other)
    self.class.new('|' * (to_i * other.to_i))
  end

  def /(other)
    self.class.new('|' * (to_i / other.to_i))
  end
end

tally = Tally.new('||')
puts tally * 2            #=> "||||"
puts tally > 1            #=> true

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

modulo(numeric) → real Show source
static VALUE
num_modulo(VALUE x, VALUE y)
{
    VALUE q = num_funcall1(x, id_div, y);
    return rb_funcall(x, '-', 1,
                      rb_funcall(y, '*', 1, q));
}

x.modulo(y) означает x-y*(x/y).floor.

Эквивалентно num.divmod(numeric)[1].

См. Numeric#divmod.

+num → num Show source
static VALUE
num_uplus(VALUE num)
{
    return num;
}

Унарный плюс — возвращает получатель.

-num → numeric Show source
static VALUE
num_uminus(VALUE num)
{
    VALUE zero;

    zero = INT2FIX(0);
    do_coerce(&zero, &num, TRUE);

    return num_funcall1(zero, '-', num);
}

Унарный минус — возвращает получатель, с отрицательным знаком.

number <=> other → 0 or nil Show source
static VALUE
num_cmp(VALUE x, VALUE y)
{
    if (x == y) return INT2FIX(0);
    return Qnil;
}

Возвращает ноль, если number равно other, иначе возвращает nil.

abs → numeric Show source
static VALUE
num_abs(VALUE num)
{
    if (rb_num_negative_int_p(num)) {
        return num_funcall0(num, idUMinus);
    }
    return num;
}

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

12.abs         #=> 12
(-34.56).abs   #=> 34.56
-34.56.abs     #=> 34.56

Numeric#magnitude является псевдонимом для Numeric#abs.

abs2 → real Show source
static VALUE
numeric_abs2(VALUE self)
{
    return f_mul(self, self);
}

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

angle → 0 or float Show source
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return DBL2NUM(M_PI);
}

Возвращает 0, если значение положительное, pi в противном случае.

arg → 0 or float Show source
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return DBL2NUM(M_PI);
}

Возвращает 0, если значение положительное, pi в противном случае.

ceil([ndigits]) → integer or float Show source
static VALUE
num_ceil(int argc, VALUE *argv, VALUE num)
{
    return flo_ceil(argc, argv, rb_Float(num));
}

Возвращает наименьшее число, большее или равное num, с точностью до ndigits десятичных знаков (по умолчанию: 0).

Numeric реализует это, преобразуя свое значение в Float и вызывая Float#ceil.

clone(freeze: true) → num Show source
static VALUE
num_clone(int argc, VALUE *argv, VALUE x)
{
    return rb_immutable_obj_clone(argc, argv, x);
}

Возвращает получатель. freeze не может быть false.

coerce(numeric) → array Show source
static VALUE
num_coerce(VALUE x, VALUE y)
{
    if (CLASS_OF(x) == CLASS_OF(y))
        return rb_assoc_new(y, x);
    x = rb_Float(x);
    y = rb_Float(y);
    return rb_assoc_new(y, x);
}

Если numeric имеет тот же тип, что и num, возвращает массив [numeric, num]. В противном случае возвращает массив с обоими numeric и num, представленными как объекты Float.

Этот механизм приведения типов используется Ruby для обработки числовых операций со смешанными типами: он предназначен для поиска совместимого общего типа между двумя операндами оператора.

1.coerce(2.5)   #=> [2.5, 1.0]
1.2.coerce(3)   #=> [3.0, 1.2]
1.coerce(2)     #=> [2, 1]
conj → self Show source
conjugate → self
static VALUE
numeric_conj(VALUE self)
{
    return self;
}

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

conjugate → self Show source
static VALUE
numeric_conj(VALUE self)
{
    return self;
}

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

denominator → integer Show source
static VALUE
numeric_denominator(VALUE self)
{
    return f_denominator(f_to_r(self));
}

Возвращает знаменатель (всегда положительный).

div(numeric) → integer Show source
static VALUE
num_div(VALUE x, VALUE y)
{
    if (rb_equal(INT2FIX(0), y)) rb_num_zerodiv();
    return rb_funcall(num_funcall1(x, '/', y), rb_intern("floor"), 0);
}

Использует / для выполнения деления, затем преобразует результат в целое число. Numeric не определяет оператор /; это оставляется подклассам.

Эквивалентно num.divmod(numeric)[0].

См. Numeric#divmod.

divmod(numeric) → array Show source
static VALUE
num_divmod(VALUE x, VALUE y)
{
    return rb_assoc_new(num_div(x, y), num_modulo(x, y));
}

Возвращает массив, содержащий частное и остаток, полученные путем деления num на numeric.

Если q, r = x.divmod(y), то

q = floor(x/y)
x = q*y + r

Частное округляется к отрицательной бесконечности, как показано в следующей таблице:

 a    |  b  |  a.divmod(b)  |   a/b   | a.modulo(b) | a.remainder(b)
------+-----+---------------+---------+-------------+---------------
 13   |  4  |   3,    1     |   3     |    1        |     1
------+-----+---------------+---------+-------------+---------------
 13   | -4  |  -4,   -3     |  -4     |   -3        |     1
------+-----+---------------+---------+-------------+---------------
-13   |  4  |  -4,    3     |  -4     |    3        |    -1
------+-----+---------------+---------+-------------+---------------
-13   | -4  |   3,   -1     |   3     |   -1        |    -1
------+-----+---------------+---------+-------------+---------------
 11.5 |  4  |   2,    3.5   |   2.875 |    3.5      |     3.5
------+-----+---------------+---------+-------------+---------------
 11.5 | -4  |  -3,   -0.5   |  -2.875 |   -0.5      |     3.5
------+-----+---------------+---------+-------------+---------------
-11.5 |  4  |  -3,    0.5   |  -2.875 |    0.5      |    -3.5
------+-----+---------------+---------+-------------+---------------
-11.5 | -4  |   2,   -3.5   |   2.875 |   -3.5      |    -3.5

Примеры

11.divmod(3)        #=> [3, 2]
11.divmod(-3)       #=> [-4, -1]
11.divmod(3.5)      #=> [3, 0.5]
(-11).divmod(3.5)   #=> [-4, 3.0]
11.5.divmod(3.5)    #=> [3, 1.0]
dup → num Show source
static VALUE
num_dup(VALUE x)
{
    return x;
}

Возвращает получатель.

eql?(numeric) → true or false Show source
static VALUE
num_eql(VALUE x, VALUE y)
{
    if (TYPE(x) != TYPE(y)) return Qfalse;

    if (RB_TYPE_P(x, T_BIGNUM)) {
        return rb_big_eql(x, y);
    }

    return rb_equal(x, y);
}

Возвращает true, если num и numeric имеют один и тот же тип и равные значения. Сравните это с Numeric#==, который выполняет преобразование типов.

1 == 1.0        #=> true
1.eql?(1.0)     #=> false
1.0.eql?(1.0)   #=> true
fdiv(numeric) → float Show source
static VALUE
num_fdiv(VALUE x, VALUE y)
{
    return rb_funcall(rb_Float(x), '/', 1, y);
}

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

finite? → true or false Show source
static VALUE
num_finite_p(VALUE num)
{
    return Qtrue;
}

Возвращает true, если num является конечным числом, иначе возвращает false.

floor([ndigits]) → integer or float Show source
static VALUE
num_floor(int argc, VALUE *argv, VALUE num)
{
    return flo_floor(argc, argv, rb_Float(num));
}

Возвращает наибольшее число, меньшее или равное num, с точностью до ndigits десятичных знаков (по умолчанию: 0).

Numeric реализует это, преобразуя свое значение в Float и вызывая Float#floor.

i → Complex(0, num) Show source
static VALUE
num_imaginary(VALUE num)
{
    return rb_complex_new(INT2FIX(0), num);
}

Возвращает соответствующее мнимое число. Недоступно для комплексных чисел.

-42.i  #=> (0-42i)
2.0.i  #=> (0+2.0i)
imag → 0 Show source
imaginary → 0
static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

Возвращает ноль.

imaginary → 0 Show source
static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

Возвращает ноль.

infinite? → -1, 1, or nil Показать исходный код
static VALUE
num_infinite_p(VALUE num)
{
    return Qnil;
}

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

integer? → true или false Показать исходный код
static VALUE
num_int_p(VALUE num)
{
    return Qfalse;
}

Возвращает true, если значение является целым числом (Integer).

1.0.integer?   #=> false
1.integer?     #=> true
magnitude → числовое Показать исходный код
static VALUE
num_abs(VALUE num)
{
    if (rb_num_negative_int_p(num)) {
        return num_funcall0(num, idUMinus);
    }
    return num;
}

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

12.abs         #=> 12
(-34.56).abs   #=> 34.56
-34.56.abs     #=> 34.56

Numeric#magnitude является псевдонимом для Numeric#abs.

modulo(числовое) → вещественное Показать исходный код
static VALUE
num_modulo(VALUE x, VALUE y)
{
    VALUE q = num_funcall1(x, id_div, y);
    return rb_funcall(x, '-', 1,
                      rb_funcall(y, '*', 1, q));
}

Операция modulo означает остаток от деления.

Эквивалентно операции получения остатка от деления.

См. Numeric#divmod.

negative? → true или false Показать исходный код
static VALUE
num_negative_p(VALUE num)
{
    return rb_num_negative_int_p(num) ? Qtrue : Qfalse;
}

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

nonzero? → self или nil Показать исходный код
static VALUE
num_nonzero_p(VALUE num)
{
    if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
        return Qnil;
    }
    return num;
}

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

Это поведение полезно при объединении сравнений:

a = %w( z Bb bB bb BB a aA Aa AA A )
b = a.sort {|a,b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
b   #=> ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"]
numerator → целое число Показать исходный код
static VALUE
numeric_numerator(VALUE self)
{
    return f_numerator(f_to_r(self));
}

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

phase → 0 или число с плавающей точкой Показать исходный код
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return DBL2NUM(M_PI);
}

Возвращает 0, если значение положительное, и pi в противном случае.

polar → массив Показать исходный код
static VALUE
numeric_polar(VALUE self)
{
    VALUE abs, arg;

    if (RB_INTEGER_TYPE_P(self)) {
        abs = rb_int_abs(self);
        arg = numeric_arg(self);
    }
    else if (RB_FLOAT_TYPE_P(self)) {
        abs = rb_float_abs(self);
        arg = float_arg(self);
    }
    else if (RB_TYPE_P(self, T_RATIONAL)) {
        abs = rb_rational_abs(self);
        arg = numeric_arg(self);
    }
    else {
        abs = f_abs(self);
        arg = f_arg(self);
    }
    return rb_assoc_new(abs, arg);
}

Возвращает массив; [num.abs, num.arg].

positive? → true или false Показать исходный код
static VALUE
num_positive_p(VALUE num)
{
    const ID mid = '>';

    if (FIXNUM_P(num)) {
        if (method_basic_p(rb_cInteger))
            return (SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0) ? Qtrue : Qfalse;
    }
    else if (RB_TYPE_P(num, T_BIGNUM)) {
        if (method_basic_p(rb_cInteger))
            return BIGNUM_POSITIVE_P(num) && !rb_bigzero_p(num) ? Qtrue : Qfalse;
    }
    return rb_num_compare_with_zero(num, mid);
}

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

quo(int_or_rat) → rat Показать исходный код
quo(flo) → flo
VALUE
rb_numeric_quo(VALUE x, VALUE y)
{
    if (RB_TYPE_P(x, T_COMPLEX)) {
        return rb_complex_div(x, y);
    }

    if (RB_FLOAT_TYPE_P(y)) {
        return rb_funcallv(x, idFdiv, 1, &y);
    }

    if (canonicalization) {
        x = rb_rational_raw1(x);
    }
    else {
        x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
    }
    return nurat_div(x, y);
}

Возвращает наиболее точное деление (рациональное для целых чисел, число с плавающей точкой для чисел с плавающей точкой).

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

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

real? → true или false Показать исходный код
static VALUE
num_real_p(VALUE num)
{
    return Qtrue;
}

Возвращает true, если значение является вещественным числом (т.е. не Complex).

rect → массив Показать исходный код
rectangular → массив
static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}

Возвращает массив; [num, 0].

rectangular → массив Показать исходный код
static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}

Возвращает массив; [num, 0].

remainder(числовое) → вещественное Показать исходный код
static VALUE
num_remainder(VALUE x, VALUE y)
{
    VALUE z = num_funcall1(x, '%', y);

    if ((!rb_equal(z, INT2FIX(0))) &&
        ((rb_num_negative_int_p(x) &&
          rb_num_positive_int_p(y)) ||
         (rb_num_positive_int_p(x) &&
          rb_num_negative_int_p(y)))) {
        return rb_funcall(z, '-', 1, y);
    }
    return z;
}

Операция remainder означает остаток от деления.

См. Numeric#divmod.

round([ndigits]) → целое число или число с плавающей точкой Показать исходный код
static VALUE
num_round(int argc, VALUE* argv, VALUE num)
{
    return flo_round(argc, argv, rb_Float(num));
}

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

Numeric реализует это путём преобразования своего значения в Float и вызова Float#round.

step(by: шаг, to: предел) {|i| блок } → self Показать исходный код
step(by: шаг, to: предел) → итератор
step(by: шаг, to: предел) → арифметическая последовательность
step(предел=nil, шаг=1) {|i| блок } → self
step(предел=nil, шаг=1) → итератор
step(предел=nil, шаг=1) → арифметическая последовательность
static VALUE
num_step(int argc, VALUE *argv, VALUE from)
{
    VALUE to, step;
    int desc, inf;

    if (!rb_block_given_p()) {
        VALUE by = Qundef;

        num_step_extract_args(argc, argv, &to, &step, &by);
        if (by != Qundef) {
            step = by;
        }
        if (NIL_P(step)) {
            step = INT2FIX(1);
        }
        if ((NIL_P(to) || rb_obj_is_kind_of(to, rb_cNumeric)) &&
            rb_obj_is_kind_of(step, rb_cNumeric)) {
            return rb_arith_seq_new(from, ID2SYM(rb_frame_this_func()), argc, argv,
                                    num_step_size, from, to, step, FALSE);
        }

        return SIZED_ENUMERATOR(from, 2, ((VALUE [2]){to, step}), num_step_size);
    }

    desc = num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
    if (rb_equal(step, INT2FIX(0))) {
        inf = 1;
    }
    else if (RB_TYPE_P(to, T_FLOAT)) {
        double f = RFLOAT_VALUE(to);
        inf = isinf(f) && (signbit(f) ? desc : !desc);
    }
    else inf = 0;

    if (FIXNUM_P(from) && (inf || FIXNUM_P(to)) && FIXNUM_P(step)) {
        long i = FIX2LONG(from);
        long diff = FIX2LONG(step);

        if (inf) {
            for (;; i += diff)
                rb_yield(LONG2FIX(i));
        }
        else {
            long end = FIX2LONG(to);

            if (desc) {
                for (; i >= end; i += diff)
                    rb_yield(LONG2FIX(i));
            }
            else {
                for (; i <= end; i += diff)
                    rb_yield(LONG2FIX(i));
            }
        }
    }
    else if (!ruby_float_step(from, to, step, FALSE, FALSE)) {
        VALUE i = from;

        if (inf) {
            for (;; i = rb_funcall(i, '+', 1, step))
                rb_yield(i);
        }
        else {
            ID cmp = desc ? '<' : '>';

            for (; !RTEST(rb_funcall(i, cmp, 1, to)); i = rb_funcall(i, '+', 1, step))
                rb_yield(i);
        }
    }
    return from;
}

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

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

В рекомендуемом стиле с ключевыми аргументами можно опустить один или оба аргумента, `предел` и `шаг` (по умолчанию бесконечность). В стиле с фиксированным позиционным аргументом шаг равный нулю (т.е. num.step(limit, 0)) запрещён по соображениям совместимости.

Если все аргументы являются целыми числами, цикл выполняется с использованием целочисленного счётчика.

Если хотя бы один из аргументов является числом с плавающей точкой, все аргументы преобразуются в числа с плавающей точкой, и цикл выполняется floor(n + n*Float::EPSILON) + 1 раз, где n = (предел - начальное значение)/шаг.

В противном случае цикл начинается с начального значения, использует оператор меньше (<) или больше (>) для сравнения счётчика с пределом и увеличивает счётчик на величину шага.

Если блок не предоставлен, возвращается Enumerator вместо этого. В частности, итератор является Enumerator::ArithmeticSequence, если и `начальное значение` и `предел` являются числами (Numeric) или nil.

Например:

p 1.step.take(4)
p 10.step(by: -1).take(4)
3.step(to: 5) {|i| print i, " " }
1.step(10, 2) {|i| print i, " " }
Math::E.step(to: Math::PI, by: 0.2) {|f| print f, " " }

Что выведет:

[1, 2, 3, 4]
[10, 9, 8, 7]
3 4 5
1 3 5 7 9
2.718281828459045 2.9182818284590453 3.118281828459045
to_c → комплексное Показать исходный код
static VALUE
numeric_to_c(VALUE self)
{
    return rb_complex_new1(self);
}

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

to_int → целое число Показать исходный код
static VALUE
num_to_int(VALUE num)
{
    return num_funcall0(num, id_to_i);
}

Вызывает метод дочернего класса to_i для преобразования num в целое число.

1.0.class          #=> Float
1.0.to_int.class   #=> Integer
1.0.to_i.class     #=> Integer
truncate([ndigits]) → целое или число с плавающей точкой Показать исходный код
static VALUE
num_truncate(int argc, VALUE *argv, VALUE num)
{
    return flo_truncate(argc, argv, rb_Float(num));
}

Возвращает num , усечённое (к нулю) до точности ndigits десятичных разрядов (по умолчанию: 0).

Numeric реализует это, преобразуя своё значение в Float и вызывая Float#truncate.

zero? → true или false Показать исходный код
static VALUE
num_zero_p(VALUE num)
{
    if (FIXNUM_P(num)) {
        if (FIXNUM_ZERO_P(num)) {
            return Qtrue;
        }
    }
    else if (RB_TYPE_P(num, T_BIGNUM)) {
        if (rb_bigzero_p(num)) {
            /* this should not happen usually */
            return Qtrue;
        }
    }
    else if (rb_equal(num, INT2FIX(0))) {
        return Qtrue;
    }
    return Qfalse;
}

Возвращает true , если num имеет нулевое значение.

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