class Numeric
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
Что здесь
Сначала, что находится в другом месте. Класс Numeric:
-
Наследуется от class Object.
-
Включает module Comparable.
Здесь класс Numeric предоставляет методы для:
Запрос
-
finite?: Возвращает true, еслиselfне является бесконечным или не числом. -
infinite?: Возвращает -1,nilили +1, в зависимости от того, является лиself-Infinity<tt>, finite, or <tt>+Infinity. -
integer?: Возвращает, является лиselfцелым числом. -
negative?: Возвращает, является лиselfотрицательным. -
nonzero?: Возвращает, является лиselfне нулем. -
positive?: Возвращает, является лиselfположительным. -
real?: Возвращает, является лиselfвещественным значением. -
zero?: Возвращает, является лиselfнулем.
Сравнение
-
<=>: Возвращает:-
-1, если
selfменьше заданного значения. -
0, если
selfравно заданному значению. -
1, если
selfбольше заданного значения. -
nil, еслиselfи заданное значение не сравнимы.
-
-
eql?: Возвращает, имеют лиselfи заданное значение одинаковое значение и тип.
Преобразование
-
%(псевдонимmodulo): Возвращает остаток от деленияselfна заданное значение. -
-@: Возвращает значениеself, взятое с обратным знаком. -
abs(псевдонимmagnitude): Возвращает абсолютное значениеself. -
abs2: Возвращает квадратself. -
angle(псевдонимargиphase): Возвращает 0, еслиselfположительно, Math::PI в противном случае. -
ceil: Возвращает наименьшее число, большее или равноеself, с заданной точностью. -
coerce: Возвращает массив[coerced_self, coerced_other]для заданного другого значения. -
conj(псевдонимconjugate): Возвращает комплексно сопряженное числоself. -
denominator: Возвращает знаменатель (всегда положительный)Rationalпредставленияself. -
div: Возвращает значениеself, деленное на заданное значение и преобразованное в целое число. -
divmod: Возвращает массив[quotient, modulus], полученный в результате деленияselfна заданный делитель. -
fdiv: Возвращает результат деленияselfна заданный делитель в видеFloat. -
floor: Возвращает наибольшее число, меньшее или равноеself, с заданной точностью. -
i: ВозвращаетComplexобъектComplex(0, self). заданное значение. -
numerator: Возвращает числительRationalпредставленияself; имеет тот же знак, что иself. -
polar: Возвращает массив[self.abs, self.arg]. -
quo: Возвращает значениеself, деленное на заданное значение. -
real: Возвращает вещественную частьself. -
rect(псевдонимrectangular): Возвращает массив[self, 0]. -
remainder: Возвращаетself-arg*(self/arg).truncateдля заданногоarg. -
round: Возвращает значениеself, округленное до ближайшего значения с заданной точностью. -
to_int: ВозвращаетIntegerпредставлениеself, усекая при необходимости. -
truncate: Возвращаетself, усеченное (в сторону нуля) с заданной точностью.
Другие операции
Методы экземпляров публичного класса
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));
} Возвращает остаток от деления self по модулю other в виде вещественного числа.
Из классов Ядра и Стандартной библиотеки только Rational использует эту реализацию.
Для рациональных r и вещественных чисел n, эти выражения эквивалентны:
r % n r-n*(r/n).floor r.divmod(n)[1]
См. Numeric#divmod.
Примеры:
r = Rational(1, 2) # => (1/2) r2 = Rational(2, 3) # => (2/3) r % r2 # => (1/2) r % 2 # => (1/2) r % 2.0 # => 0.5 r = Rational(301,100) # => (301/100) r2 = Rational(7,5) # => (7/5) r % r2 # => (21/100) r % -r2 # => (-119/100) (-r) % r2 # => (119/100) (-r) %-r2 # => (-21/100)
Numeric#modulo — псевдоним для Numeric#%.
static VALUE
num_uplus(VALUE num)
{
return num;
} Возвращает self.
static VALUE
num_uminus(VALUE num)
{
VALUE zero;
zero = INT2FIX(0);
do_coerce(&zero, &num, TRUE);
return num_funcall1(zero, '-', num);
} Унарный минус — возвращает значение объекта, смененного на противоположное.
static VALUE
num_cmp(VALUE x, VALUE y)
{
if (x == y) return INT2FIX(0);
return Qnil;
} Возвращает ноль, если self равно other, и nil в противном случае.
Ни один подкласс в Ядре или Стандартной библиотеке Ruby не использует эту реализацию.
static VALUE
num_abs(VALUE num)
{
if (rb_num_negative_int_p(num)) {
return num_funcall0(num, idUMinus);
}
return num;
} Возвращает абсолютное значение self.
12.abs #=> 12 (-34.56).abs #=> 34.56 -34.56.abs #=> 34.56
Numeric#magnitude — псевдоним для Numeric#abs.
static VALUE
numeric_abs2(VALUE self)
{
return f_mul(self, self);
} Возвращает квадрат значения.
Возвращает 0, если значение положительное, и pi в противном случае.
static VALUE
numeric_arg(VALUE self)
{
if (f_positive_p(self))
return INT2FIX(0);
return DBL2NUM(M_PI);
} Возвращает 0, если значение положительное, и pi в противном случае.
static VALUE
num_ceil(int argc, VALUE *argv, VALUE num)
{
return flo_ceil(argc, argv, rb_Float(num));
} Возвращает наименьшее число, которое больше или равно self с точностью до digits десятичных знаков.
Numeric выполняет это, преобразуя self в Float и вызывая Float#ceil.
static VALUE
num_clone(int argc, VALUE *argv, VALUE x)
{
return rb_immutable_obj_clone(argc, argv, x);
} Возвращает self.
Вызывает исключение, если значение для freeze не является ни true, ни nil.
Связанно с: Numeric#dup.
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);
} Возвращает массив из двух элементов, содержащих два числовых элемента, сформированных из двух операндов self и other, одного совместимого типа.
Из классов Ядра и Стандартной библиотеки Integer, Rational и Complex используют эту реализацию.
Примеры:
i = 2 # => 2 i.coerce(3) # => [3, 2] i.coerce(3.0) # => [3.0, 2.0] i.coerce(Rational(1, 2)) # => [0.5, 2.0] i.coerce(Complex(3, 4)) # Raises RangeError. r = Rational(5, 2) # => (5/2) r.coerce(2) # => [(2/1), (5/2)] r.coerce(2.0) # => [2.0, 2.5] r.coerce(Rational(2, 3)) # => [(2/3), (5/2)] r.coerce(Complex(3, 4)) # => [(3+4i), ((5/2)+0i)] c = Complex(2, 3) # => (2+3i) c.coerce(2) # => [(2+0i), (2+3i)] c.coerce(2.0) # => [(2.0+0i), (2+3i)] c.coerce(Rational(1, 2)) # => [((1/2)+0i), (2+3i)] c.coerce(Complex(3, 4)) # => [(3+4i), (2+3i)]
Вызывает исключение, если преобразование типа не выполняется.
# File numeric.rb, line 76 def conjugate self end
Возвращает self.
static VALUE
numeric_denominator(VALUE self)
{
return f_denominator(f_to_r(self));
} Возвращает знаменатель (всегда положительный).
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);
} Возвращает частное self/other в виде целого числа (через floor), используя метод / в производном классе self. (Сам Numeric не определяет метод /.)
Из классов Ядра и Стандартной библиотеки только Float и Rational используют эту реализацию.
static VALUE
num_divmod(VALUE x, VALUE y)
{
return rb_assoc_new(num_div(x, y), num_modulo(x, y));
} Возвращает массив из двух элементов [q, r], где
q = (self/other).floor # Quotient r = self % other # Remainder
Из классов Ядра и Стандартной библиотеки только Rational использует эту реализацию.
Примеры:
Rational(11, 1).divmod(4) # => [2, (3/1)] Rational(11, 1).divmod(-4) # => [-3, (-1/1)] Rational(-11, 1).divmod(4) # => [-3, (1/1)] Rational(-11, 1).divmod(-4) # => [2, (-3/1)] Rational(12, 1).divmod(4) # => [3, (0/1)] Rational(12, 1).divmod(-4) # => [-3, (0/1)] Rational(-12, 1).divmod(4) # => [-3, (0/1)] Rational(-12, 1).divmod(-4) # => [3, (0/1)] Rational(13, 1).divmod(4.0) # => [3, 1.0] Rational(13, 1).divmod(Rational(4, 11)) # => [35, (3/11)]
static VALUE
num_eql(VALUE x, VALUE y)
{
if (TYPE(x) != TYPE(y)) return Qfalse;
if (RB_BIGNUM_TYPE_P(x)) {
return rb_big_eql(x, y);
}
return rb_equal(x, y);
} Возвращает true , если self и other — объекты одного типа с равными значениями.
Из классов Ядра и Стандартной библиотеки только Integer, Rational и Complex используют эту реализацию.
Примеры:
1.eql?(1) # => true 1.eql?(1.0) # => false 1.eql?(Rational(1, 1)) # => false 1.eql?(Complex(1, 0)) # => false
Метод eql? отличается от +==+ тем, что eql? требует соответствия типов, в то время как +==+ — нет.
static VALUE
num_fdiv(VALUE x, VALUE y)
{
return rb_funcall(rb_Float(x), '/', 1, y);
} Возвращает частное self/other в виде вещественного числа, используя метод / в производном классе self. (Сам Numeric не определяет метод /.)
Из классов Ядра и Стандартной библиотеки только BigDecimal использует эту реализацию.
# File numeric.rb, line 41 def finite? true end
Возвращает true, если num является конечным числом, в противном случае возвращает false.
static VALUE
num_floor(int argc, VALUE *argv, VALUE num)
{
return flo_floor(argc, argv, rb_Float(num));
} Возвращает наибольшее число, меньшее или равное self с точностью до digits десятичных знаков.
Numeric реализует это, преобразуя self в Float и вызывая Float#floor.
static VALUE
num_imaginary(VALUE num)
{
return rb_complex_new(INT2FIX(0), num);
} Возвращает Complex(0, self):
2.i # => (0+2i) -2.i # => (0-2i) 2.0.i # => (0+2.0i) Rational(1, 2).i # => (0+(1/2)*i) Complex(3, 4).i # Raises NoMethodError.
# File numeric.rb, line 63 def imaginary 0 end
Возвращает ноль.
# File numeric.rb, line 52 def infinite? nil end
Возвращает -1, 1 или nil в зависимости от того, является ли значение конечным, бесконечным или неопределенным.
# File numeric.rb, line 31 def integer? false end
Возвращает true, если num является Integer.
1.0.integer? #=> false 1.integer? #=> true
Возвращает абсолютное значение self.
12.abs #=> 12 (-34.56).abs #=> 34.56 -34.56.abs #=> 34.56
Numeric#magnitude является псевдонимом для Numeric#abs.
Возвращает остаток от деления self на other как вещественное число.
Из классов Ядра и Стандартной библиотеки только Rational использует эту реализацию.
Для рациональных r и вещественного числа n, эти выражения эквивалентны:
r % n r-n*(r/n).floor r.divmod(n)[1]
См. Numeric#divmod.
Примеры:
r = Rational(1, 2) # => (1/2) r2 = Rational(2, 3) # => (2/3) r % r2 # => (1/2) r % 2 # => (1/2) r % 2.0 # => 0.5 r = Rational(301,100) # => (301/100) r2 = Rational(7,5) # => (7/5) r % r2 # => (21/100) r % -r2 # => (-119/100) (-r) % r2 # => (119/100) (-r) %-r2 # => (-21/100)
Numeric#modulo является псевдонимом для Numeric#%.
static VALUE
num_negative_p(VALUE num)
{
return RBOOL(rb_num_negative_int_p(num));
} Возвращает true, если self меньше 0, false в противном случае.
static VALUE
num_nonzero_p(VALUE num)
{
if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
return Qnil;
}
return num;
} Возвращает self, если self не равно нулю, nil в противном случае; использует метод zero? для оценки.
Возвращаемое значение позволяет цепочке методов.
a = %w[z Bb bB bb BB a aA Aa AA A]
a.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
# => ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"]
Из классов Ядра и Стандартной библиотеки Integer, Float, Rational и Complex используют эту реализацию.
static VALUE
numeric_numerator(VALUE self)
{
return f_numerator(f_to_r(self));
} Возвращает числитель.
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].
static VALUE
num_positive_p(VALUE num)
{
const ID mid = '>';
if (FIXNUM_P(num)) {
if (method_basic_p(rb_cInteger))
return RBOOL((SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0));
}
else if (RB_BIGNUM_TYPE_P(num)) {
if (method_basic_p(rb_cInteger))
return RBOOL(BIGNUM_POSITIVE_P(num) && !rb_bigzero_p(num));
}
return rb_num_compare_with_zero(num, mid);
} Возвращает true, если self больше 0, false в противном случае.
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);
} Возвращает наиболее точное деление (рациональное для целых чисел, число с плавающей точкой для чисел с плавающей точкой).
# File numeric.rb, line 18 def real self end
Возвращает self.
# File numeric.rb, line 8 def real? true end
Возвращает true, если num является вещественным числом (т.е. не Complex).
static VALUE
numeric_rect(VALUE self)
{
return rb_assoc_new(self, INT2FIX(0));
} Возвращает массив; [num, 0].
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)))) {
if (RB_FLOAT_TYPE_P(y)) {
if (isinf(RFLOAT_VALUE(y))) {
return x;
}
}
return rb_funcall(z, '-', 1, y);
}
return z;
} Возвращает остаток от деления self на other.
Из классов Ядра и Стандартной библиотеки только Float и Rational используют эту реализацию.
Примеры:
11.0.remainder(4) # => 3.0 11.0.remainder(-4) # => 3.0 -11.0.remainder(4) # => -3.0 -11.0.remainder(-4) # => -3.0 12.0.remainder(4) # => 0.0 12.0.remainder(-4) # => 0.0 -12.0.remainder(4) # => -0.0 -12.0.remainder(-4) # => -0.0 13.0.remainder(4.0) # => 1.0 13.0.remainder(Rational(4, 1)) # => 1.0 Rational(13, 1).remainder(4) # => (1/1) Rational(13, 1).remainder(-4) # => (1/1) Rational(-13, 1).remainder(4) # => (-1/1) Rational(-13, 1).remainder(-4) # => (-1/1)
static VALUE
num_round(int argc, VALUE* argv, VALUE num)
{
return flo_round(argc, argv, rb_Float(num));
} Возвращает self, округленное до ближайшего значения с точностью до digits десятичных знаков.
Numeric реализует это, преобразуя self в Float и вызывая Float#round.
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 (!UNDEF_P(by)) {
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_FLOAT_TYPE_P(to)) {
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;
} Generates a sequence of numbers; with a block given, traverses the sequence.
Of the Core and Standard Library classes,
Integer, Float, and Rational use this implementation.
A quick example:
squares = []
1.step(by: 2, to: 10) {|i| squares.push(i*i) }
squares # => [1, 9, 25, 49, 81]
The generated sequence:
- Begins with +self+.
- Continues at intervals of +step+ (which may not be zero).
- Ends with the last number that is within or equal to +limit+;
that is, less than or equal to +limit+ if +step+ is positive,
greater than or equal to +limit+ if +step+ is negative.
If +limit+ is not given, the sequence is of infinite length.
If a block is given, calls the block with each number in the sequence;
returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence.
<b>Keyword Arguments</b>
With keyword arguments +by+ and +to+,
their values (or defaults) determine the step and limit:
# Both keywords given.
squares = []
4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4
squares # => [16, 36, 64, 100]
cubes = []
3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3
cubes # => [27.0, 3.375, 0.0, -3.375, -27.0]
squares = []
1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) }
squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
squares = []
Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) }
squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
# Only keyword to given.
squares = []
4.step(to: 10) {|i| squares.push(i*i) } # => 4
squares # => [16, 25, 36, 49, 64, 81, 100]
# Only by given.
# Only keyword by given
squares = []
4.step(by:2) {|i| squares.push(i*i); break if i > 10 }
squares # => [16, 36, 64, 100, 144]
# No block given.
e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3))
e.class # => Enumerator::ArithmeticSequence
<b>Positional Arguments</b>
With optional positional arguments +limit+ and +step+,
their values (or defaults) determine the step and limit:
squares = []
4.step(10, 2) {|i| squares.push(i*i) } # => 4
squares # => [16, 36, 64, 100]
squares = []
4.step(10) {|i| squares.push(i*i) }
squares # => [16, 25, 36, 49, 64, 81, 100]
squares = []
4.step {|i| squares.push(i*i); break if i > 10 } # => nil
squares # => [16, 25, 36, 49, 64, 81, 100, 121] Примечания к реализации
If all the arguments are integers, the loop operates using an integer counter. If any of the arguments are floating point numbers, all are converted to floats, and the loop is executed <i>floor(n + n*Float::EPSILON) + 1</i> times, where <i>n = (limit - self)/step</i>.
static VALUE
numeric_to_c(VALUE self)
{
return rb_complex_new1(self);
} Возвращает значение в виде комплексного числа.
static VALUE
num_to_int(VALUE num)
{
return num_funcall0(num, id_to_i);
} Возвращает self как целое число; выполняет преобразование с помощью метода to_i в производном классе.
Из классов Ядра и Стандартной библиотеки только Rational и Complex используют эту реализацию.
Примеры:
Rational(1, 2).to_int # => 0 Rational(2, 1).to_int # => 2 Complex(2, 0).to_int # => 2 Complex(2, 1) # Raises RangeError (non-zero imaginary part)
static VALUE
num_truncate(int argc, VALUE *argv, VALUE num)
{
return flo_truncate(argc, argv, rb_Float(num));
} Возвращает self, усеченное (к нулю) с точностью digits десятичных знаков.
Numeric реализует это, преобразуя self в Float и вызывая Float#truncate.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.