class Numeric include Comparable # Always raises TypeError, as dup'ing Numerics is not allowed. def initialize_copy(other) raise TypeError, "copy of #{self.class} is not allowed" end private :initialize_copy def +@ self end def -@ 0 - self end def divmod(other) [div(other), self % other] end def eql?(other) return false unless other.instance_of? self.class self == other end def <=>(other) # It's important this method NOT contain the coercion protocols! # MRI doesn't and doing so breaks stuff! return 0 if self.equal? other return nil end def step(limit=nil, step=nil, to: nil, by: nil) unless block_given? return to_enum(:step, limit, step, to: to, by: by) do Rubinius::Mirror::Numeric.reflect(self).step_size(limit, step, to, by) end end m = Rubinius::Mirror::Numeric.reflect(self) values = m.step_fetch_args(limit, step, to, by) value = values[0] limit = values[1] step = values[2] asc = values[3] is_float = values[4] if step == 0 while true yield value end end if is_float n = m.step_float_size(value, limit, step, asc) if n > 0 if step.infinite? yield value else i = 0 if asc while i < n d = i * step + value d = limit if limit < d yield d i += 1 end else while i < n d = i * step + value d = limit if limit > d yield d i += 1 end end end end else if asc until value > limit yield value value += step end else until value < limit yield value value += step end end end return self end def truncate Float(self).truncate end # Delegate #to_int to #to_i in subclasses def to_int to_i end def integer? false end def zero? self == 0 end def nonzero? zero? ? nil : self end def round to_f.round end def abs self < 0 ? -self : self end def floor FloatValue(self).floor end def ceil FloatValue(self).ceil end def remainder(other) mod = self % other if mod != 0 and ((self < 0 and other > 0) or (self > 0 and other < 0)) mod - other else mod end end #-- # We deviate from MRI behavior here because we ensure that Fixnum op Bignum # => Bignum (possibly normalized to Fixnum) # # Note these differences on MRI, where a is a Fixnum, b is a Bignum # # a.coerce b => [Float, Float] # b.coerce a => [Bignum, Bignum] #++ def coerce(other) if other.instance_of? self.class return [other, self] end [Float(other), Float(self)] end ## # This method mimics the semantics of MRI's do_coerce function # in numeric.c. Note these differences between it and #coerce: # # 1.2.coerce("2") => [2.0, 1.2] # 1.2 + "2" => TypeError: String can't be coerced into Float # # See also Integer#coerce def math_coerce(other, error=:coerce_error) begin values = other.coerce(self) rescue if error == :coerce_error raise TypeError, "#{other.class} can't be coerced into #{self.class}" else raise ArgumentError, "comparison of #{self.class} with #{other.class} failed" end end unless Rubinius::Type.object_kind_of?(values, Array) && values.length == 2 raise TypeError, "coerce must return [x, y]" end return values[1], values[0] end private :math_coerce def redo_coerced(meth, right) b, a = math_coerce(right) a.__send__ meth, b end private :redo_coerced def redo_compare(meth, right) b, a = math_coerce(right, :compare_error) a.__send__ meth, b end def div(other) raise ZeroDivisionError, "divided by 0" if other == 0 (self / other).floor end def fdiv(other) self.to_f / other end def quo(other) Rubinius.privately do Rational.convert(self, 1, false) / other end end def modulo(other) self - other * self.div(other) end alias_method :%, :modulo def i Complex(0, self) end def to_c Complex(self, 0) end def real self end def imag 0 end alias_method :imaginary, :imag def arg if self < 0 Math::PI else 0 end end alias_method :angle, :arg alias_method :phase, :arg def polar return abs, arg end def conjugate self end alias_method :conj, :conjugate def rect [self, 0] end alias_method :rectangular, :rect def abs2 self * self end alias_method :magnitude, :abs def numerator to_r.numerator end def denominator to_r.denominator end def real? true end def positive? self > 0 end def negative? self < 0 end end