Spec-Zone.ru › Ruby 3

класс 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

Общедоступные методы экземпляров

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.

Также алиас: modulo
+num → num Показать исходный код
static VALUE
num_uplus(VALUE num)
{
    return num;
}

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

-num → numeric Показать исходный код
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 Показать исходный код
static VALUE
num_cmp(VALUE x, VALUE y)
{
    if (x == y) return INT2FIX(0);
    return Qnil;
}

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

abs → numeric Показать исходный код
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.

Также алиас: magnitude
abs2 → real Показать исходный код
static VALUE
numeric_abs2(VALUE self)
{
    return f_mul(self, self);
}

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

angle → 0 or float

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

Псевдоним для: arg
arg → 0 or float Показать исходный код
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return DBL2NUM(M_PI);
}

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

Также алиас: angle, phase
ceil([ndigits]) → integer or float Показать исходный код
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 Показать исходный код
static VALUE
num_clone(int argc, VALUE *argv, VALUE x)
{
    return rb_immutable_obj_clone(argc, argv, x);
}

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

coerce(numeric) → array Показать исходный код
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

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

Псевдоним для: conjugate
static VALUE
numeric_conj(VALUE self)
{
    return self;
}

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

Также алиас: conj
denominator → integer Показать исходный код
static VALUE
numeric_denominator(VALUE self)
{
    return f_denominator(f_to_r(self));
}

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

div(numeric) → integer Показать исходный код
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 Показать исходный код
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 Показать исходный код
static VALUE
num_dup(VALUE x)
{
    return x;
}

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

eql?(numeric) → true or false Показать исходный код
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 Показать исходный код
static VALUE
num_fdiv(VALUE x, VALUE y)
{
    return rb_funcall(rb_Float(x), '/', 1, y);
}

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

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

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

floor([ndigits]) → integer or float Показать исходный код
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) Показать исходный код
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

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

Псевдоним для: imaginary
static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

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

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

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

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

Возвращает true если num является Integer.

1.0.integer?   #=> false
1.integer?     #=> true
magnitude → numeric

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

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

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

Псевдоним для: abs
modulo(numeric) → real

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

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

См. Numeric#divmod.

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

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

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

Возвращает self если num не равно нулю, 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 → integer Показать исходный код
static VALUE
numeric_numerator(VALUE self)
{
    return f_numerator(f_to_r(self));
}

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

phase → 0 or float

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

Псевдоним для: arg
polar → array Показать исходный код
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 or 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 если num больше 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);
    }

    x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
    return rb_rational_div(x, y);
}

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

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

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

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

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

rect → array

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

Псевдоним для: rectangular
static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}

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

Также является псевдонимом для: rect
remainder(numeric) → real Показать исходный код
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;
}

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

См. Numeric#divmod.

round([ndigits]) → integer or float Показать исходный код
static VALUE
num_round(int argc, VALUE* argv, VALUE num)
{
    return flo_round(argc, argv, rb_Float(num));
}

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

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

step(by: step, to: limit) {|i| block } → self Показать исходный код
step(by: step, to: limit) → an_enumerator
step(by: step, to: limit) → an_arithmetic_sequence
step(limit=nil, step=1) {|i| block } → self
step(limit=nil, step=1) → an_enumerator
step(limit=nil, step=1) → an_arithmetic_sequence
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);
        }
        else if (rb_equal(step, INT2FIX(0))) {
            rb_raise(rb_eArgError, "step can't be 0");
        }
        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 (по умолчанию 1) при каждом вызове.

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

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

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

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

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

Если блок не задан, вместо него возвращается Enumerator. В частности, перечислитель является Enumerator::ArithmeticSequence, если и limit, и step являются типом 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 → complex Показать исходный код
static VALUE
numeric_to_c(VALUE self)
{
    return rb_complex_new1(self);
}

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

to_int → integer Показать исходный код
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]) → integer or float Показать исходный код
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 or false Показать исходный код
static VALUE
num_zero_p(VALUE num)
{
    if (rb_equal(num, INT2FIX(0))) {
        return Qtrue;
    }
    return Qfalse;
}

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

Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API