Class: Numeric

Inherits:
Object show all
Includes:
Comparable
Defined in:
numeric.c,
numeric.c

Overview

Numeric is the class from which all higher-level numeric classes should inherit.

Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as Integer are implemented as immediates, which means that each Integer is a single immutable object which is always passed by value.

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

There can only ever be one instance of the integer 1, for example. Ruby ensures this by preventing instantiation and duplication.

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

For this reason, Numeric should be used when defining other numeric classes.

Classes which inherit from Numeric must implement coerce, which returns a two-member Array containing an object that has been coerced into an instance of the new class and self (see #coerce).

Inheriting classes should also implement arithmetic operator methods (+, -, * and /) and the <=> operator (see Comparable). These methods may rely on coerce to ensure interoperability with instances of other numeric classes.

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

Direct Known Subclasses

Complex, Float, Integer, Rational

Instance Method Summary collapse

Methods included from Comparable

#<, #<=, #==, #>, #>=, #between?

Instance Method Details

#modulo(numeric) ⇒ Object

x.modulo(y) means x-y*(x/y).floor

Equivalent to num.divmod(numeric)[1].

See Numeric#divmod.


463
464
465
466
467
468
469
# File 'numeric.c', line 463

static VALUE
num_modulo(VALUE x, VALUE y)
{
    return rb_funcall(x, '-', 1,
		      rb_funcall(y, '*', 1,
				 rb_funcall(x, id_div, 1, y)));
}

#+Numeric

Unary Plus—Returns the receiver's value.


379
380
381
382
383
# File 'numeric.c', line 379

static VALUE
num_uplus(VALUE num)
{
    return num;
}

#-Numeric

Unary Minus—Returns the receiver's value, negated.


407
408
409
410
411
412
413
414
415
416
# File 'numeric.c', line 407

static VALUE
num_uminus(VALUE num)
{
    VALUE zero;

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

    return rb_funcall(zero, '-', 1, num);
}

#<=>(other) ⇒ 0?

Returns zero if number equals other, otherwise nil is returned if the two values are incomparable.


1125
1126
1127
1128
1129
1130
# File 'numeric.c', line 1125

static VALUE
num_cmp(VALUE x, VALUE y)
{
    if (x == y) return INT2FIX(0);
    return Qnil;
}

#absNumeric #magnitudeNumeric

Returns the absolute value of num.

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

Numeric#magnitude is an alias of Numeric#abs.


586
587
588
589
590
591
592
593
# File 'numeric.c', line 586

static VALUE
num_abs(VALUE num)
{
    if (negative_int_p(num)) {
	return rb_funcall(num, idUMinus, 0);
    }
    return num;
}

#abs2Object

Returns square of self.


2004
2005
2006
2007
2008
# File 'complex.c', line 2004

static VALUE
numeric_abs2(VALUE self)
{
    return f_mul(self, self);
}

#arg0, Float #angle0, Float #phase0, Float

Returns 0 if the value is positive, pi otherwise.


2020
2021
2022
2023
2024
2025
2026
# File 'complex.c', line 2020

static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
	return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

#arg0, Float #angle0, Float #phase0, Float

Returns 0 if the value is positive, pi otherwise.


2020
2021
2022
2023
2024
2025
2026
# File 'complex.c', line 2020

static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
	return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

#ceilInteger

Returns the smallest possible Integer that is greater than or equal to num.

Numeric achieves this by converting itself to a Float then invoking Float#ceil.

1.ceil        #=> 1
1.2.ceil      #=> 2
(-1.2).ceil   #=> -1
(-1.0).ceil   #=> -1

1933
1934
1935
1936
1937
# File 'numeric.c', line 1933

static VALUE
num_ceil(VALUE num)
{
    return flo_ceil(rb_Float(num));
}

#coerce(numeric) ⇒ Array

If a numeric is the same type as num, returns an array containing numeric and num. Otherwise, returns an array with both a numeric and num represented as Float objects.

This coercion mechanism is used by Ruby to handle mixed-type numeric operations: it is intended to find a compatible common type between the two operands of the operator.

1.coerce(2.5)   #=> [2.5, 1.0]
1.2.coerce(3)   #=> [3.0, 1.2]
1.coerce(2)     #=> [2, 1]

231
232
233
234
235
236
237
238
239
# File 'numeric.c', line 231

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);
}

#conjself #conjugateself

Returns self.


2060
2061
2062
2063
2064
# File 'complex.c', line 2060

static VALUE
numeric_conj(VALUE self)
{
    return self;
}

#conjself #conjugateself

Returns self.


2060
2061
2062
2063
2064
# File 'complex.c', line 2060

static VALUE
numeric_conj(VALUE self)
{
    return self;
}

#denominatorInteger

Returns the denominator (always positive).


1819
1820
1821
1822
1823
# File 'rational.c', line 1819

static VALUE
numeric_denominator(VALUE self)
{
    return f_denominator(f_to_r(self));
}

#div(numeric) ⇒ Integer

Uses / to perform division, then converts the result to an integer. numeric does not define the / operator; this is left to subclasses.

Equivalent to num.divmod(numeric)[0].

See Numeric#divmod.


444
445
446
447
448
449
# File 'numeric.c', line 444

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);
}

#divmod(numeric) ⇒ Array

Returns an array containing the quotient and modulus obtained by dividing num by numeric.

If q, r = * x.divmod(y), then

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

The quotient is rounded toward -infinity, as shown in the following table:

 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

Examples

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]

537
538
539
540
541
# File 'numeric.c', line 537

static VALUE
num_divmod(VALUE x, VALUE y)
{
    return rb_assoc_new(num_div(x, y), num_modulo(x, y));
}

#eql?(numeric) ⇒ Boolean

Returns true if num and numeric are the same type and have equal values.

1 == 1.0          #=> true
1.eql?(1.0)       #=> false
(1.0).eql?(1.0)   #=> true

1109
1110
1111
1112
1113
1114
1115
# File 'numeric.c', line 1109

static VALUE
num_eql(VALUE x, VALUE y)
{
    if (TYPE(x) != TYPE(y)) return Qfalse;

    return rb_equal(x, y);
}

#fdiv(numeric) ⇒ Float

Returns float division.


425
426
427
428
429
# File 'numeric.c', line 425

static VALUE
num_fdiv(VALUE x, VALUE y)
{
    return rb_funcall(rb_Float(x), '/', 1, y);
}

#floorInteger

Returns the largest integer less than or equal to num.

Numeric implements this by converting an Integer to a Float and invoking Float#floor.

1.floor      #=> 1
(-1).floor   #=> -1

1910
1911
1912
1913
1914
# File 'numeric.c', line 1910

static VALUE
num_floor(VALUE num)
{
    return flo_floor(rb_Float(num));
}

#iComplex(0]

Returns the corresponding imaginary number. Not available for complex numbers.


393
394
395
396
397
# File 'numeric.c', line 393

static VALUE
num_imaginary(VALUE num)
{
    return rb_complex_new(INT2FIX(0), num);
}

#imag0 #imaginary0

Returns zero.


1992
1993
1994
1995
1996
# File 'complex.c', line 1992

static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

#imag0 #imaginary0

Returns zero.


1992
1993
1994
1995
1996
# File 'complex.c', line 1992

static VALUE
numeric_imag(VALUE self)
{
    return INT2FIX(0);
}

#initialize_copy(y) ⇒ Object

Numerics are immutable values, which should not be copied.

Any attempt to use this method on a Numeric will raise a TypeError.


364
365
366
367
368
369
370
# File 'numeric.c', line 364

static VALUE
num_init_copy(VALUE x, VALUE y)
{
    rb_raise(rb_eTypeError, "can't copy %"PRIsVALUE, rb_obj_class(x));

    UNREACHABLE;
}

#integer?Boolean

Returns true if num is an Integer (including Fixnum and Bignum).

(1.0).integer? #=> false
(1).integer?   #=> true

566
567
568
569
570
# File 'numeric.c', line 566

static VALUE
num_int_p(VALUE num)
{
    return Qfalse;
}

#absNumeric #magnitudeNumeric

Returns the absolute value of num.

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

Numeric#magnitude is an alias of Numeric#abs.


586
587
588
589
590
591
592
593
# File 'numeric.c', line 586

static VALUE
num_abs(VALUE num)
{
    if (negative_int_p(num)) {
	return rb_funcall(num, idUMinus, 0);
    }
    return num;
}

#modulo(numeric) ⇒ Object

x.modulo(y) means x-y*(x/y).floor

Equivalent to num.divmod(numeric)[1].

See Numeric#divmod.


463
464
465
466
467
468
469
# File 'numeric.c', line 463

static VALUE
num_modulo(VALUE x, VALUE y)
{
    return rb_funcall(x, '-', 1,
		      rb_funcall(y, '*', 1,
				 rb_funcall(x, id_div, 1, y)));
}

#negative?Boolean

Returns true if num is less than 0.


682
683
684
685
686
# File 'numeric.c', line 682

static VALUE
num_negative_p(VALUE num)
{
    return negative_int_p(num) ? Qtrue : Qfalse;
}

#nonzero?self?

Returns self if num is not zero, nil otherwise.

This behavior is useful when chaining comparisons:

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"]

626
627
628
629
630
631
632
633
# File 'numeric.c', line 626

static VALUE
num_nonzero_p(VALUE num)
{
    if (RTEST(rb_funcallv(num, rb_intern("zero?"), 0, 0))) {
	return Qnil;
    }
    return num;
}

#numeratorInteger

Returns the numerator.


1807
1808
1809
1810
1811
# File 'rational.c', line 1807

static VALUE
numeric_numerator(VALUE self)
{
    return f_numerator(f_to_r(self));
}

#arg0, Float #angle0, Float #phase0, Float

Returns 0 if the value is positive, pi otherwise.


2020
2021
2022
2023
2024
2025
2026
# File 'complex.c', line 2020

static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
	return INT2FIX(0);
    return rb_const_get(rb_mMath, id_PI);
}

#polarArray

Returns an array; [num.abs, num.arg].


2047
2048
2049
2050
2051
# File 'complex.c', line 2047

static VALUE
numeric_polar(VALUE self)
{
    return rb_assoc_new(f_abs(self), f_arg(self));
}

#positive?Boolean

Returns true if num is greater than 0.


659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'numeric.c', line 659

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);
}

#quo(int_or_rat) ⇒ Object #quo(flo) ⇒ Object

Returns most exact division (rational for integers, float for floats).


1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
# File 'rational.c', line 1834

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);
}

#realself

Returns self.


1979
1980
1981
1982
1983
# File 'complex.c', line 1979

static VALUE
numeric_real(VALUE self)
{
    return self;
}

#real?Boolean

Returns true if num is a Real number. (i.e. not Complex).


550
551
552
553
554
# File 'numeric.c', line 550

static VALUE
num_real_p(VALUE num)
{
    return Qtrue;
}

#rectArray #rectangularArray

Returns an array; [num, 0].


2035
2036
2037
2038
2039
# File 'complex.c', line 2035

static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}

#rectArray #rectangularArray

Returns an array; [num, 0].


2035
2036
2037
2038
2039
# File 'complex.c', line 2035

static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}

#remainder(numeric) ⇒ Object

x.remainder(y) means x-y*(x/y).truncate

See Numeric#divmod.


480
481
482
483
484
485
486
487
488
489
490
491
492
493
# File 'numeric.c', line 480

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;
}

#round([ndigits]) ⇒ Integer, Float

Rounds num to a given precision in decimal digits (default 0 digits).

Precision may be negative. Returns a floating point number when ndigits is more than zero.

Numeric implements this by converting itself to a Float and invoking Float#round.


1952
1953
1954
1955
1956
# File 'numeric.c', line 1952

static VALUE
num_round(int argc, VALUE* argv, VALUE num)
{
    return flo_round(argc, argv, rb_Float(num));
}

#singleton_method_added(name) ⇒ Object

Trap attempts to add methods to Numeric objects. Always raises a TypeError.

Numerics should be values; singleton_methods should not be added to them.


345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'numeric.c', line 345

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;
}

#step(by: step, to: limit) {|i| ... } ⇒ self #step(by: step, to: limit) ⇒ Object #step(limit = nil, step = 1) {|i| ... } ⇒ self #step(limit = nil, step = 1) ⇒ Object

Invokes the given block with the sequence of numbers starting at num, incremented by step (defaulted to 1) on each call.

The loop finishes when the value to be passed to the block is greater than limit (if step is positive) or less than limit (if step is negative), where limit is defaulted to infinity.

In the recommended keyword argument style, either or both of step and limit (default infinity) can be omitted. In the fixed position argument style, zero as a step (i.e. num.step(limit, 0)) is not allowed for historical compatibility reasons.

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 the following expression:

floor(n + n*epsilon)+ 1

Where the n is the following:

n = (limit - num)/step

Otherwise, the loop starts at num, uses either the less-than (<) or greater-than (>) operator to compare the counter against limit, and increments itself using the + operator.

If no block is given, an Enumerator is returned instead.

For example:

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, " " }

Will produce:

[1, 2, 3, 4]
[10, 9, 8, 7]
3 4 5
1 3 5 7 9
2.71828182845905 2.91828182845905 3.11828182845905

Overloads:

  • #step(by: step, to: limit) {|i| ... } ⇒ self

    Yields:

    • (i)
  • #step(limit = nil, step = 1) {|i| ... } ⇒ self

    Yields:

    • (i)

2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
# File 'numeric.c', line 2185

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;
}

#to_cObject

Returns the value as a complex.


1552
1553
1554
1555
1556
# File 'complex.c', line 1552

static VALUE
numeric_to_c(VALUE self)
{
    return rb_complex_new1(self);
}

#to_intInteger

Invokes the child class's to_i method to convert num to an integer.

1.0.class => Float
1.0.to_int.class => Fixnum
1.0.to_i.class => Fixnum

646
647
648
649
650
# File 'numeric.c', line 646

static VALUE
num_to_int(VALUE num)
{
    return rb_funcallv(num, id_to_i, 0, 0);
}

#truncateInteger

Returns num truncated to an Integer.

Numeric implements this by converting its value to a Float and invoking Float#truncate.


1968
1969
1970
1971
1972
# File 'numeric.c', line 1968

static VALUE
num_truncate(VALUE num)
{
    return flo_truncate(rb_Float(num));
}

#zero?Boolean

Returns true if num has a zero value.


603
604
605
606
607
608
609
610
# File 'numeric.c', line 603

static VALUE
num_zero_p(VALUE num)
{
    if (rb_equal(num, INT2FIX(0))) {
	return Qtrue;
    }
    return Qfalse;
}