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 类

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

查询

  • finite?: 除非 self 是无穷大或不是数字,否则返回 true。

  • infinite?: 返回 -1、nil 或 +1,具体取决于 self-Infinity<tt>、有限还是 <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 (别名为 argphase): 如果 self 为正数,则返回 0,否则返回 Math::PI。

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

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

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

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

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

  • divmod: 返回一个数组 [商, 余数],该数组是将 self 除以给定除数的结果。

  • 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: 返回 self-arg*(self/arg).truncate,其中 arg 为给定的参数。

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

  • to_c: 返回 selfComplex 表示。

  • to_int: 返回 selfInteger 表示,必要时进行截断。

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

其他

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

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

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

公共实例方法

self % other → real_numeric click to toggle source

返回 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 click to toggle source

返回 self

static VALUE
num_uplus(VALUE num)
{
    return num;
}
-self → numeric click to toggle source

一元减号 - 返回接收者,取反。

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 click to toggle source

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

Ruby Core 或标准库中的任何子类都不使用此实现。

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);
}
也称为:angle, phase
ceil(digits = 0) → integer or float 点击切换源代码

返回大于或等于 self 的最小数字,精度为 digits 个小数位。

Numeric 通过将 self 转换为 Float 并调用 Float#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 的值为 truenil 之外,则会引发异常。

相关: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 组成,它们具有共同的兼容类型。

在 Core 和标准库类中,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_3_0/numeric.rb, line 68
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.

static VALUE
num_dup(VALUE x)
{
    return x;
}
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_3_0/numeric.rb, line 38
def finite?
  true
end
floor(digits = 0) → integer or float 点击切换源代码

返回小于或等于 self 的最大数字,精度为 digits 个小数位。

Numeric 通过将 self 转换为 Float 并调用 Float#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_3_0/numeric.rb, line 57
def imaginary
  0
end
也称为别名:imag
infinite? → -1, 1, 或 nil 点击切换源代码

根据 self 是否为有限、-Infinity+Infinity,返回 nil、-1 或 1。

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

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

1.0.integer? # => false
1.integer?   # => true
# File ruby_3_3_0/numeric.rb, line 29
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 或 false 点击切换源代码

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

static VALUE
num_negative_p(VALUE num)
{
    return RBOOL(rb_num_negative_int_p(num));
}
nonzero? → self 或 nil 点击切换源代码

如果 self 不是零值,则返回 self,否则返回 nil;使用方法 zero? 进行评估。

返回的 self 允许方法进行链式调用

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

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

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 或 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_3_0/numeric.rb, line 17
def real
  self
end
real? → true 或 false 点击切换源代码

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

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

返回数组 [self, 0]

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

返回数组 [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) → 整数或浮点数 点击切换源代码

返回 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) → 枚举器
step(to = nil, by: 1) {|n| ... } → self
step(to = nil, by: 1) → 枚举器
step(by: 1, to: ) {|n| ... } → self
step(by: 1, to: ) → 枚举器
step(by: , to: nil) {|n| ... } → self
step(by: , to: nil) → 枚举器
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 +by+ (which may not be zero).
- Ends with the last number that is within or equal to +to+;
  that is, less than or equal to +to+ if +by+ is positive,
  greater than or equal to +to+ if +by+ is negative.
  If +to+ is +nil+, 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 +to+ and +by+,
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
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 → 复数 点击切换源代码

返回 self 作为 Complex 对象。

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

返回 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)         # Raises RangeError (non-zero imaginary part)
static VALUE
num_to_int(VALUE num)
{
    return num_funcall0(num, id_to_i);
}
truncate(digits = 0) → 整数或浮点数 点击切换源代码

返回 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 或 false 点击切换源代码

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

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

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