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,它返回一个包含被强制转换为新类的实例和 self 的对象的双元素 Array (请参阅 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

在这里,类 Numeric 提供了以下方法:

查询

  • finite?:如果 self 不是无限数或不是数字,则返回 true。

  • infinite?:根据 self-Infinity、有限的还是 +Infinity,返回 -1、nil 或 +1。

  • integer?:返回 self 是否为整数。

  • negative?:返回 self 是否为负数。

  • nonzero?:返回 self 是否不为零。

  • positive?:返回 self 是否为正数。

  • real?:返回 self 是否为实数。

  • zero?:返回 self 是否为零。

比较

  • #<=>:返回

    • 如果 self 小于给定值,则返回 -1。

    • 如果 self 等于给定值,则返回 0。

    • 如果 self 大于给定值,则返回 1。

    • 如果 self 和给定值不可比较,则返回 nil

  • eql?:返回 self 和给定值是否具有相同的值和类型。

转换

  • %(别名为 modulo):返回 self 除以给定值的余数。

  • -@:返回 self 的值,取反。

  • abs(别名为 magnitude):返回 self 的绝对值。

  • abs2:返回 self 的平方。

  • angle(别名为 argphase):如果 self 为正数,则返回 0,否则返回 Math::PI。

  • ceil:返回大于或等于 self 的最小数,精确到给定的精度。

  • coerce:为给定的其他值返回数组 [coerced_self, coerced_other]

  • conj(别名为 conjugate):返回 self 的复共轭。

  • denominator:返回 selfRational 表示的分母(始终为正)。

  • div:返回 self 除以给定值并转换为整数的值。

  • divmod:返回将 self 除以给定的除数所产生的数组 [quotient, modulus]

  • fdiv:返回 self 除以给定除数的 Float 结果。

  • floor:返回小于或等于 self 的最大数,精确到给定的精度。

  • i:返回 Complex 对象 Complex(0, self)。给定的值。

  • imaginary(别名为 imag):返回 self 的虚部。

  • numerator:返回 selfRational 表示的分子;与 self 具有相同的符号。

  • polar:返回数组 [self.abs, self.arg]

  • quo:返回 self 除以给定值的值。

  • real:返回 self 的实部。

  • rect(别名为 rectangular):返回数组 [self, 0]

  • remainder:对于给定的 arg,返回 self-arg*(self/arg).truncate

  • round:返回 self 四舍五入到给定精度的最接近的值。

  • to_c:返回 selfComplex 表示。

  • to_int:返回 selfInteger 表示,如有必要则截断。

  • truncate:返回 self 截断(向零方向)到给定精度。

其他

  • clone:返回 self;不允许冻结。

  • dup(别名为 +@):返回 self

  • step:使用指定的数字序列调用给定的块。

公共实例方法

self % other → real_numeric 点击切换源代码

以实数形式返回 selfother

在核心和标准库类中,只有 Rational 使用此实现。

对于 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)
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
+self → self 点击切换源代码

返回 self

# File ruby_3_4_1/numeric.rb, line 89
def +@
  self
end
-self → numeric 点击切换源代码

一元负号—返回取反的接收器。

static VALUE
num_uminus(VALUE num)
{
    VALUE zero;

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

    return num_funcall1(zero, '-', num);
}
self <=> other → zero or nil 点击切换源代码

如果 selfother 相同,则返回零,否则返回 nil

Ruby 核心或标准库中没有子类使用此实现。

static VALUE
num_cmp(VALUE x, VALUE y)
{
    if (x == y) return INT2FIX(0);
    return Qnil;
}
abs → numeric 点击切换源代码

返回 self 的绝对值。

12.abs        #=> 12
(-34.56).abs  #=> 34.56
-34.56.abs    #=> 34.56
static VALUE
num_abs(VALUE num)
{
    if (rb_num_negative_int_p(num)) {
        return num_funcall0(num, idUMinus);
    }
    return num;
}
别名为:magnitude
abs2 → real 点击切换源代码

返回 self 的平方。

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

如果 self 为正数,则返回零,否则返回 Math::PI。

别名为:arg
arg → 0 or Math::PI 点击切换源代码

如果 self 为正数,则返回零,否则返回 Math::PI。

static VALUE
numeric_arg(VALUE self)
{
    if (f_positive_p(self))
        return INT2FIX(0);
    return DBL2NUM(M_PI);
}
别名为:anglephase
ceil(ndigits = 0) → float or integer 点击切换源代码

返回大于或等于 self 的最小浮点数或整数,由给定的 ndigits 指定,ndigits 必须是 可转换为整数的对象

等效于 self.to_f.ceil(ndigits)

相关:floorFloat#ceil

static VALUE
num_ceil(int argc, VALUE *argv, VALUE num)
{
    return flo_ceil(argc, argv, rb_Float(num));
}
clone(freeze: true) → self 点击切换源代码

返回 self

如果 freeze 的值既不是 true 也不是 nil,则引发异常。

相关:Numeric#dup

static VALUE
num_clone(int argc, VALUE *argv, VALUE x)
{
    return rb_immutable_obj_clone(argc, argv, x);
}
coerce(other) → array 点击切换源代码

返回一个包含两个数字元素的 2 元素数组,这两个元素由两个操作数 selfother 组成,具有兼容的通用类型。

在核心和标准库类中,IntegerRationalComplex 使用此实现。

示例

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

如果任何类型转换失败,则引发异常。

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);
}
conj → self
别名:conjugate
conjugate -> self 点击切换源代码

返回 self

# File ruby_3_4_1/numeric.rb, line 78
def conjugate
  self
end
也别名为:conj
denominator → integer 点击切换源代码

返回分母(始终为正数)。

static VALUE
numeric_denominator(VALUE self)
{
    return f_denominator(f_to_r(self));
}
div(other) → integer 点击切换源代码

返回 self/other 的商,以整数形式(通过 floor),使用 self 的派生类中的方法 /。(Numeric 本身未定义方法 /。)

在核心和标准库类中,只有 FloatRational 使用此实现。

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);
}
divmod(other) → array 点击切换源代码

返回一个包含 2 个元素的数组 [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_divmod(VALUE x, VALUE y)
{
    return rb_assoc_new(num_div(x, y), num_modulo(x, y));
}
dup → self 点击切换源代码

返回 self

相关:Numeric#clone

# File ruby_3_4_1/numeric.rb, line 9
def dup
  self
end
eql?(other) → true or false 点击切换源代码

如果 selfother 是相同类型且具有相同的值,则返回 true

在核心和标准库类中,只有 IntegerRationalComplex 使用此实现。

示例

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_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);
}
fdiv(other) → float 点击切换源代码

返回 self/other 的商,以浮点数形式,使用 self 的派生类中的方法 /。(Numeric 本身未定义方法 /。)

在核心和标准库类中,只有 BigDecimal 使用此实现。

static VALUE
num_fdiv(VALUE x, VALUE y)
{
    return rb_funcall(rb_Float(x), '/', 1, y);
}
finite? → true or false 点击切换源代码

如果 self 是有限数,则返回 true,否则返回 false

# File ruby_3_4_1/numeric.rb, line 48
def finite?
  true
end
floor(ndigits = 0) → float or integer 点击切换源代码

返回小于或等于 self 的最大浮点数或整数,由给定的 ndigits 指定,ndigits 必须是可转换为整数的对象

等效于 self.to_f.floor(ndigits)

相关:ceilFloat#floor

static VALUE
num_floor(int argc, VALUE *argv, VALUE num)
{
    return flo_floor(argc, argv, rb_Float(num));
}
i → complex 点击切换源代码

返回 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.
static VALUE
num_imaginary(VALUE num)
{
    return rb_complex_new(INT2FIX(0), num);
}
imag → 0
别名:imaginary
imaginary -> 0 点击切换源代码

返回零。

# File ruby_3_4_1/numeric.rb, line 67
def imaginary
  0
end
也别名为:imag
infinite? → -1, 1, or nil 点击切换源代码

如果 self 是有限数,则返回 nil;如果 self-Infinity,则返回 -1;如果 self+Infinity,则返回 1。

# File ruby_3_4_1/numeric.rb, line 58
def infinite?
  nil
end
integer? → true or false 点击切换源代码

如果 self 是一个 Integer,则返回 true

1.0.integer? # => false
1.integer?   # => true
# File ruby_3_4_1/numeric.rb, line 39
def integer?
  false
end
magnitude()

返回 self 的绝对值。

12.abs        #=> 12
(-34.56).abs  #=> 34.56
-34.56.abs    #=> 34.56
别名:abs
modulo(p1)

以实数形式返回 selfother

在核心和标准库类中,只有 Rational 使用此实现。

对于 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)
别名:%
negative? → true or false 点击切换源代码

如果 self 小于 0,则返回 true,否则返回 false

static VALUE
num_negative_p(VALUE num)
{
    return RBOOL(rb_num_negative_int_p(num));
}
nonzero? → self or nil 点击切换源代码
Returns +self+ if +self+ is not a zero value, +nil+ otherwise;
uses method <tt>zero?</tt> for the evaluation.

The returned +self+ allows the method to be chained:

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

Of the Core and Standard Library classes,
Integer, Float, Rational, and Complex use this implementation.

相关:zero?

static VALUE
num_nonzero_p(VALUE num)
{
    if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
        return Qnil;
    }
    return num;
}
numerator → integer 点击切换源代码

返回分子。

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

如果 self 为正数,则返回零,否则返回 Math::PI。

别名为:arg
polar → array 点击切换源代码

返回数组 [self.abs, self.arg]

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);
}
positive? → true or false 点击切换源代码

如果 self 大于 0,则返回 true,否则返回 false

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);
}
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 点击切换源代码

返回 self

# File ruby_3_4_1/numeric.rb, line 27
def real
  self
end
real? → true or false 点击切换源代码

如果 self 是实数(即不是 Complex),则返回 true

# File ruby_3_4_1/numeric.rb, line 18
def real?
  true
end
rect → array

返回数组 [self, 0]

别名:rectangular
rectangular -> array 点击切换源代码

返回数组 [self, 0]

static VALUE
numeric_rect(VALUE self)
{
    return rb_assoc_new(self, INT2FIX(0));
}
也别名为:rect
remainder(other) → real_number 点击切换源代码

返回 self 除以 other 后的余数。

在核心和标准库类中,只有 FloatRational 使用此实现。

示例

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_remainder(VALUE x, VALUE y)
{
    if (!rb_obj_is_kind_of(y, rb_cNumeric)) {
        do_coerce(&x, &y, TRUE);
    }
    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;
}
round(digits = 0) → integer or float 点击切换源代码

返回 self 四舍五入到具有 digits 位小数精度的最接近的值。

Numeric 通过将 self 转换为 Float 并调用 Float#round 来实现此操作。

static VALUE
num_round(int argc, VALUE* argv, VALUE num)
{
    return flo_round(argc, argv, rb_Float(num));
}
step(to = nil, by = 1) {|n| ... } → self 点击切换源代码
step(to = nil, by = 1) → enumerator
step(to = nil, by: 1) {|n| ... } → self
step(to = nil, by: 1) → enumerator
step(by: 1, to: ) {|n| ... } → self
step(by: 1, to: ) → enumerator
step(by: , to: nil) {|n| ... } → self
step(by: , to: nil) → enumerator

生成一个数字序列;如果给定了块,则遍历该序列。

在核心和标准库类中,IntegerFloatRational 使用此实现。

一个简单的例子

squares = []
1.step(by: 2, to: 10) {|i| squares.push(i*i) }
squares # => [1, 9, 25, 49, 81]

生成的序列

  • self 开始。

  • by 的间隔继续(不能为零)。

  • 以最后一个小于或等于 to 的数字结束;也就是说,如果 by 为正数,则小于或等于 to,如果 by 为负数,则大于或等于 to。如果 tonil,则序列是无限长的。

如果给定了块,则使用序列中的每个数字调用该块;返回 self。如果没有给定块,则返回一个 Enumerator::ArithmeticSequence

关键字参数

使用关键字参数 byto,它们的值(或默认值)确定步长和限制。

# 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

位置参数

使用可选的位置参数 toby,它们的值(或默认值)确定步长和限制。

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]

实现说明

如果所有参数都是整数,则循环使用整数计数器操作。

如果任何参数是浮点数,则全部转换为浮点数,并且循环执行 floor(n + n*Float::EPSILON) + 1 次,其中 n = (limit - self)/step

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_KW(from, 2, ((VALUE [2]){to, step}), num_step_size, FALSE);
    }

    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;
}
to_c → complex 点击切换源代码

self 作为 Complex 对象返回。

static VALUE
numeric_to_c(VALUE self)
{
    return rb_complex_new1(self);
}
to_int → integer 点击切换源代码

self 作为整数返回;使用派生类中的方法 to_i 进行转换。

在核心和标准库类中,只有 RationalComplex 使用此实现。

示例

Rational(1, 2).to_int # => 0
Rational(2, 1).to_int # => 2
Complex(2, 0).to_int  # => 2
Complex(2, 1).to_int  # Raises RangeError (non-zero imaginary part)
static VALUE
num_to_int(VALUE num)
{
    return num_funcall0(num, id_to_i);
}
truncate(digits = 0) → integer or float 点击切换源代码

返回 self 截断(向零方向)到 digits 位小数精度。

Numeric 通过将 self 转换为 Float 并调用 Float#truncate 来实现此操作。

static VALUE
num_truncate(int argc, VALUE *argv, VALUE num)
{
    return flo_truncate(argc, argv, rb_Float(num));
}
zero? → true or false 点击切换源代码

如果 zero 的值为零,则返回 true,否则返回 false

在核心和标准库类中,只有 RationalComplex 使用此实现。

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