Spec-Zone.ru › Ruby 2.3

класс Numeric

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

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

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

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

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

Integer.new(1)   #=> NoMethodError: undefined method `new' for Integer:Class
1.dup            #=> TypeError: can't dup Fixnum

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

Классы, которые наследуются от Numeric, должны реализовывать coerce, который возвращает массив из двух элементов, содержащий объект, который был преобразован в экземпляр нового класса, и 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 Показать исходный код
static VALUE
num_modulo(VALUE x, VALUE y)
{
    return rb_funcall(x, '-', 1,
                      rb_funcall(y, '*', 1,
                                 rb_funcall(x, id_div, 1, y)));
}
x.modulo(y) means x-y*(x/y).floor

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

См. #divmod.

+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 rb_funcall(zero, '-', 1, 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 (negative_int_p(num)) {
        return rb_funcall(num, idUMinus, 0);
    }
    return num;
}

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

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

#magnitude — псевдоним #abs.

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

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

angle → 0 or float Показать исходный код
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

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

arg → 0 or float Показать исходный код
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

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

ceil → integer Показать исходный код
static VALUE
num_ceil(VALUE num)
{
    return flo_ceil(rb_Float(num));
}

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

Numeric достигает этого, преобразовав себя в Float, а затем вызвав Float#ceil.

1.ceil        #=> 1
1.2.ceil      #=> 2
(-1.2).ceil   #=> -1
(-1.0).ceil   #=> -1
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);
}

Если число имеет тот же тип, что и num, возвращает массив, содержащий numeric и num. В противном случае возвращает массив с числом и 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 Показать исходный код
conjugate → self
static VALUE
numeric_conj(VALUE self)
{
    return self;
}

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

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

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

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(rb_funcall(x, '/', 1, y), rb_intern("floor"), 0);
}

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

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

См. #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]
eql?(numeric) → true or false Показать исходный код
static VALUE
num_eql(VALUE x, VALUE y)
{
    if (TYPE(x) != TYPE(y)) return Qfalse;

    return rb_equal(x, y);
}

Возвращает true если num и 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);
}

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

floor → integer Показать исходный код
static VALUE
num_floor(VALUE num)
{
    return flo_floor(rb_Float(num));
}

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

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

1.floor      #=> 1
(-1).floor   #=> -1
i → Complex(0,num) Показать исходный код
static VALUE
num_imaginary(VALUE num)
{
    return rb_complex_new(INT2FIX(0), num);
}

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

imag → 0 Показать исходный код
imaginary → 0
static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

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

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

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

initialize_copy(p1) Показать исходный код
static VALUE
num_init_copy(VALUE x, VALUE y)
{
    rb_raise(rb_eTypeError, "can't copy %"PRIsVALUE, rb_obj_class(x));

    UNREACHABLE;
}

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

Любая попытка использовать этот метод для Numeric вызовет TypeError.

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

Возвращает true если num является целым числом (включая Fixnum и Bignum).

(1.0).integer? #=> false
(1).integer?   #=> true
magnitude → numeric Показать исходный код
static VALUE
num_abs(VALUE num)
{
    if (negative_int_p(num)) {
        return rb_funcall(num, idUMinus, 0);
    }
    return num;
}

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

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

#magnitude — псевдоним #abs.

modulo(numeric) → real Показать исходный код
static VALUE
num_modulo(VALUE x, VALUE y)
{
    return rb_funcall(x, '-', 1,
                      rb_funcall(y, '*', 1,
                                 rb_funcall(x, id_div, 1, y)));
}
x.modulo(y) means x-y*(x/y).floor

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

См. #divmod.

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

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

nonzero? → self or nil Показать исходный код
static VALUE
num_nonzero_p(VALUE num)
{
    if (RTEST(rb_funcallv(num, rb_intern("zero?"), 0, 0))) {
        return Qnil;
    }
    return 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 Показать исходный код
static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

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

polar → array Показать исходный код
static VALUE
numeric_polar(VALUE self)
{
    return rb_assoc_new(f_abs(self), f_arg(self));
}

Возвращает массив; [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_cFixnum))
            return (SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0) ? Qtrue : Qfalse;
    }
    else if (RB_TYPE_P(num, T_BIGNUM)) {
        if (method_basic_p(rb_cBignum))
            return BIGNUM_POSITIVE_P(num) && !rb_bigzero_p(num) ? Qtrue : Qfalse;
    }
    return compare_with_zero(num, mid);
}

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

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

#ifdef CANON
    if (canonicalization) {
        x = rb_rational_raw1(x);
    }
    else
#endif
    {
        x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
    }
    return rb_funcall(x, '/', 1, 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, если значение является вещественным числом (т.е. не является Complex).

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

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

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

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

remainder(numeric) → real Показать исходный код
static VALUE
num_remainder(VALUE x, VALUE y)
{
    VALUE z = rb_funcall(x, '%', 1, y);

    if ((!rb_equal(z, INT2FIX(0))) &&
        ((negative_int_p(x) &&
          positive_int_p(y)) ||
         (positive_int_p(x) &&
          negative_int_p(y)))) {
        return rb_funcall(z, '-', 1, y);
    }
    return z;
}
x.remainder(y) means x-y*(x/y).truncate

См. #divmod.

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

Округляет значение до заданной точности в десятичных знаках (по умолчанию 0 знаков).

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

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

singleton_method_added(p1) Показать исходный код
static VALUE
num_sadded(VALUE x, VALUE name)
{
    ID mid = rb_to_id(name);
    /* ruby_frame = ruby_frame->prev; */ /* pop frame for "singleton_method_added" */
    rb_remove_method_id(rb_singleton_class(x), mid);
    rb_raise(rb_eTypeError,
             "can't define singleton method \"%"PRIsVALUE"\" for %"PRIsVALUE,
             rb_id2str(mid),
             rb_obj_class(x));

    UNREACHABLE;
}

Перехватывает попытки добавить методы к объектам Numeric. Всегда вызывает TypeError.

Числа должны быть значениями; к ним не должны добавляться методы singleton.

step(by: step, to: limit) {|i| block } → self Показать исходный код
step(by: step, to: limit) → an_enumerator
step(limit=nil, step=1) {|i| block } → self
step(limit=nil, step=1) → an_enumerator
static VALUE
num_step(int argc, VALUE *argv, VALUE from)
{
    VALUE to, step;
    int desc, inf;

    RETURN_SIZED_ENUMERATOR(from, argc, argv, num_step_size);

    desc = num_step_scan_args(argc, argv, &to, &step);
    if (RTEST(rb_num_coerce_cmp(step, INT2FIX(0), id_eq))) {
        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)) {
        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;
}

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

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

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

Если все аргументы — целые числа, цикл работает с целочисленным счетчиком.

Если какой-либо из аргументов — число с плавающей точкой, все аргументы преобразуются в числа с плавающей точкой, и цикл выполняется по следующему выражению:

floor(n + n*epsilon)+ 1

Где <%%CODE_BLOCK_114%%> - следующее:

n = (limit - num)/step

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

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

Например:

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.71828182845905 2.91828182845905 3.11828182845905
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 rb_funcallv(num, id_to_i, 0, 0);
}

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

1.0.class => Float
1.0.to_int.class => Fixnum
1.0.to_i.class => Fixnum
truncate → integer Показать исходный код
static VALUE
num_truncate(VALUE num)
{
    return flo_truncate(rb_Float(num));
}

Возвращает значение, усеченное до целого числа.

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, если значение равно нулю.

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