类 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
-
继承自 类 Object。
-
包含 模块 Comparable。
在这里,类 Numeric 提供了以下方法:
查询¶ ↑
-
finite?:如果self不是无穷大或不是数字,则返回 true。 -
infinite?:根据self是-Infinity<tt>、有限的还是<tt>+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和给定值是否具有相同的值和类型。
转换¶ ↑
-
-@:返回self的相反数。 -
abs2:返回self的平方。 -
ceil:返回大于或等于self的最小数,精确到给定精度。 -
coerce:为给定的其他值返回数组[coerced_self, coerced_other]。 -
denominator:返回self的Rational表示的分母(始终为正数)。 -
div:返回self除以给定值并转换为整数的值。 -
divmod:返回数组[quotient, modulus],该数组是self除以给定除数的结果。 -
floor:返回小于或等于self的最大数,精确到给定精度。 -
polar:返回数组[self.abs, self.arg]。 -
quo:返回self除以给定值的值。 -
real:返回self的实部。 -
rect(别名为rectangular):返回数组[self, 0]。 -
remainder:对于给定的arg,返回self-arg*(self/arg).truncate。 -
round:返回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 使用此实现。
对于 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_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 Core 或标准库中没有子类使用此实现。
来源
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
来源
static VALUE
numeric_arg(VALUE self)
{
if (f_positive_p(self))
return INT2FIX(0);
return DBL2NUM(M_PI);
}
如果 self 为正数,则返回零,否则返回 Math::PI。
来源
static VALUE
num_ceil(int argc, VALUE *argv, VALUE num)
{
return flo_ceil(argc, argv, rb_Float(num));
}
返回大于或等于 self 的最小浮点数或整数,由给定的 'ndigits' 指定,它必须是一个 可转换为整数的对象。
等效于 self.to_f.ceil(ndigits)。
相关:floor,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);
}
返回一个包含两个数字元素的 2 元素数组,该数组由两个操作数 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)]
如果任何类型转换失败,则引发异常。
来源
static VALUE
numeric_denominator(VALUE self)
{
return f_denominator(f_to_r(self));
}
返回分母(始终为正数)。
来源
来源
static VALUE
num_divmod(VALUE x, VALUE y)
{
return rb_assoc_new(num_div(x, y), num_modulo(x, y));
}
返回一个 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_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);
}
如果 self 和 other 是相同的类型且具有相等的值,则返回 true。
在核心和标准库类中,只有 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 的派生类中的方法 /,以浮点数形式返回商 self/other。(Numeric 本身没有定义方法 /。)
在核心和标准库类中,只有 BigDecimal 使用此实现。
来源
# File numeric.rb, line 48 def finite? true end
如果 self 是有限数,则返回 true,否则返回 false。
来源
static VALUE
num_floor(int argc, VALUE *argv, VALUE num)
{
return flo_floor(argc, argv, rb_Float(num));
}
返回小于或等于 self 的最大浮点数或整数,由给定的 'ndigits' 指定,它必须是一个 可转换为整数的对象。
等效于 self.to_f.floor(ndigits)。
相关:ceil,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 58 def infinite? nil end
返回 nil, -1, 或 1,取决于 self 是有限值, -Infinity, 还是 +Infinity。
来源
# File numeric.rb, line 39 def integer? false end
如果 self 是一个 Integer,则返回 true。
1.0.integer? # => false 1.integer? # => true
来源
static VALUE
num_negative_p(VALUE num)
{
return RBOOL(rb_num_negative_int_p(num));
}
如果 self 小于 0,则返回 true,否则返回 false。
来源
static VALUE
num_nonzero_p(VALUE num)
{
if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
return Qnil;
}
return num;
}
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
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);
}
返回数组 [self.abs, self.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);
}
如果 self 大于 0,则返回 true,否则返回 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? true end
如果 self 是实数(即不是 Complex),则返回 true。
来源
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;
}
返回 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_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;
}
生成数字序列;如果给定块,则遍历该序列。
在核心和标准库类中,Integer、Float 和 Rational 使用此实现。
一个快速示例
squares = [] 1.step(by: 2, to: 10) {|i| squares.push(i*i) } squares # => [1, 9, 25, 49, 81]
生成的序列
-
以
self开始。 -
以
by的间隔继续(by不能为零)。 -
以最后一个在
to范围内或等于to的数字结束;也就是说,如果by为正数,则小于或等于to,如果by为负数,则大于或等于to。如果to为nil,则序列是无限长度的。
如果给定块,则使用序列中的每个数字调用该块;返回 self。如果没有给定块,则返回一个 Enumerator::ArithmeticSequence。
关键字参数
使用关键字参数 by 和 to,它们的值(或默认值)确定步长和限制。
# 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
位置参数
使用可选的位置参数 to 和 by,它们的值(或默认值)确定步长和限制。
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
numeric_to_c(VALUE self)
{
return rb_complex_new1(self);
}
将 self 作为 Complex 对象返回。
来源
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).to_int # 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 来实现此方法。