rubinius/rubinius

View on GitHub
core/integer.rb

Summary

Maintainability
F
2 wks
Test Coverage
class Integer < Numeric
  def self.===(obj)
    Rubinius.asm do
      int = new_label
      done = new_label

      r0 = new_register

      r_load_local r0, 0

      b_if_int r0, r0, int
      goto done

      int.set!
      r_load_true r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  # unary operators

  def !
    false
  end

  def ~
    Rubinius.asm do
      eint = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_self r0

      n_promote r1, r0, r0

      r_load_2 r2
      n_ieq r3, r1, r2
      b_if r3, eint

      n_iinc r2, r2
      n_ine r3, r1, r2
      b_if r3, done

      r_load_int r0, r0
      n_inot r0, r0
      r_store_int r0, r0
      goto val

      eint.set!
      n_enot r0, r0

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  def -@
    Rubinius.asm do
      eint = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_self r0

      n_promote r1, r0, r0

      r_load_2 r2
      n_ieq r3, r1, r2
      b_if r3, eint

      n_iinc r2, r2
      n_ine r3, r1, r2
      b_if r3, done

      n_ineg_o r0, r0
      goto val

      eint.set!
      n_eneg r0, r0

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  def bit_length
    Rubinius.asm do
      eint = new_label
      bits = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_self r0

      n_promote r1, r0, r0

      r_load_2 r2
      n_ieq r3, r1, r2
      b_if r3, eint

      n_iinc r2, r2
      n_ine r3, r1, r2
      b_if r3, done

      r_load_int r0, r0
      n_ibits r0, r0
      r_store_int r0, r0
      goto val

      eint.set!
      r_load_0 r1
      r_store_int r1, r1
      n_promote r2, r0, r1

      r_load_2 r3
      n_ine r3, r2, r3
      b_if r3, done

      n_egt r2, r0, r1
      b_if r2, bits
      n_enot r0, r0

      bits.set!
      n_ebits r0, r0

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  # binary math operators

  def +(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_eadd r0, r0, r1
      goto val

      flt.set!
      n_dadd r0, r0, r1
      r_store_float r0, r0
      goto val

      int.set!
      n_iadd_o r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :+, other
  end

  def -(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_esub r0, r0, r1
      goto val

      flt.set!
      n_dsub r0, r0, r1
      r_store_float r0, r0
      goto val

      int.set!
      n_isub_o r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :-, other
  end

  def *(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_emul r0, r0, r1
      goto val

      flt.set!
      n_dmul r0, r0, r1
      r_store_float r0, r0
      goto val

      int.set!
      n_imul_o r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :*, other
  end

  def /(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_ediv r0, r0, r1
      goto val

      flt.set!
      n_ddiv r0, r0, r1
      r_store_float r0, r0
      goto val

      int.set!
      n_idiv_o r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :/, other
  end

  alias_method :divide, :/

  def div(o)
    if o.is_a?(Float) && o == 0.0
      raise ZeroDivisionError, "division by zero"
    end

    (self / o).floor
  end

  def fdiv(other)
    to_f / other
  end

  def %(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_emod r0, r0, r1
      goto val

      flt.set!
      n_dmod r0, r0, r1
      r_store_float r0, r0
      goto val

      int.set!
      n_imod_o r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :%, other
  end

  alias_method :modulo, :%

  def divmod(other)
    Rubinius.asm do
      int = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      n_edivmod r2, r0, r1
      goto val

      flt.set!
      n_ddivmod r2, r0, r1
      goto val

      int.set!
      n_idivmod r2, r0, r1

      val.set!
      r_store_stack r0
      r_store_stack r1
      make_array 2
      ret

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    redo_coerced :divmod, other
  end

  def **(o)
    Rubinius.asm do
      int = new_label
      eint = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_2 r3
      n_ieq r3, r3, r2
      b_if r3, eint

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      goto done

      int.set!
      r_load_0 r2
      n_ilt r3, r1, r2
      b_if r3, done

      n_ipow_o r0, r0, r1
      goto val

      eint.set!
      r_load_0 r2
      r_store_int r2, r2
      n_promote r3, r0, r2

      n_elt r3, r1, r2
      b_if r3, done

      n_epow r0, r0, r1

      val.set!
      r_ret r0

      flt.set!
      # TODO: add n_dpow
      r_store_float r0, r0
      r_store_float r1, r1
      r_store_stack r0
      r_store_stack r1
      send :**, 1
      ret

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    if o.is_a?(Float) && self < 0 && o != o.round
      return Complex.new(self, 0) ** o
    elsif o.is_a?(Integer) && o < 0
      return Rational.new(self, 1) ** o
    end

    redo_coerced :**, o
  end

  # comparison operators

  def !=(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_ene r0, r0, r1
      goto val

      flt.set!
      n_dne r0, r0, r1
      goto val

      cmp.set!
      n_ine r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other != self ? true : false
  end

  def eql?(other)
    other.is_a?(Integer) && self == other
  end

  def ==(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_eeq r0, r0, r1
      goto val

      flt.set!
      n_deq r0, r0, r1
      goto val

      cmp.set!
      n_ieq r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other == self ? true : false
  end

  alias_method :===, :==

  def <(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_elt r0, r0, r1
      goto val

      flt.set!
      n_dlt r0, r0, r1
      goto val

      cmp.set!
      n_ilt r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    b, a = math_coerce other, :compare_error
    a < b ? true : false
  end

  def <=(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_ele r0, r0, r1
      goto val

      flt.set!
      n_dle r0, r0, r1
      goto val

      cmp.set!
      n_ile r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    b, a = math_coerce other, :compare_error
    a <= b ? true : false
  end

  def >(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_egt r0, r0, r1
      goto val

      flt.set!
      n_dgt r0, r0, r1
      goto val

      cmp.set!
      n_igt r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    b, a = math_coerce other, :compare_error
    a > b ? true : false
  end

  def >=(other)
    Rubinius.asm do
      cmp = new_label
      flt = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, cmp

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ieq r3, r3, r2
      b_if r3, flt

      n_ege r0, r0, r1
      goto val

      flt.set!
      n_dge r0, r0, r1
      goto val

      cmp.set!
      n_ige r0, r0, r1

      val.set!
      r_load_bool r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    b, a = math_coerce other, :compare_error
    a >= b ? true : false
  end

  def <=>(other)
    Rubinius.asm do
      int = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_2 r3
      n_ine r3, r2, r3
      b_if r3, done

      n_ecmp r0, r0, r1
      goto val

      int.set!
      n_icmp r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    if other.kind_of? Float
      return nil if other.nan?
      return -1 if other.infinite? == 1
      return 1 if other.infinite? == -1
    end

    begin
      b, a = math_coerce other, :compare_error
      return a <=> b
    rescue ArgumentError, TypeError
      return nil
    end
  end

  # bitwise binary operators

  def &(other)
    Rubinius.asm do
      int = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_1 r3
      n_iadd r3, r3, r3
      n_ine r2, r2, r3
      b_if r2, done

      n_eand r0, r0, r1
      r_ret r0

      int.set!
      r_load_int r0, r0
      r_load_int r1, r1

      n_iand r0, r0, r1

      r_store_int r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other = Rubinius::Type.coerce_to_bitwise_operand other

    other & self
  end

  def |(other)
    Rubinius.asm do
      int = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_1 r3
      n_iadd r3, r3, r3
      n_ine r2, r2, r3
      b_if r2, done

      n_eor r0, r0, r1
      r_ret r0

      int.set!
      r_load_int r0, r0
      r_load_int r1, r1

      n_ior r0, r0, r1

      r_store_int r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other = Rubinius::Type.coerce_to_bitwise_operand other

    other | self
  end

  def ^(other)
    Rubinius.asm do
      int = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      n_promote r2, r0, r1

      r_load_1 r3
      n_iadd r3, r3, r3
      n_ine r2, r2, r3
      b_if r2, done

      n_exor r0, r0, r1
      r_ret r0

      int.set!
      r_load_int r0, r0
      r_load_int r1, r1

      n_ixor r0, r0, r1

      r_store_int r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other = Rubinius::Type.coerce_to_bitwise_operand other

    other ^ self
  end

  def <<(other)
    Rubinius.asm do
      shl = new_label
      neg = new_label
      eint = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, neg
      goto eint

      neg.set!
      r_load_int r2, r1
      r_load_0 r3

      n_ige r3, r2, r3
      b_if r3, shl

      n_ineg r1, r2
      r_store_int r1, r1
      n_ishr_o r0, r0, r1
      r_ret r0

      shl.set!
      n_ishl_o r0, r0, r1
      r_ret r0

      eint.set!
      n_promote r2, r0, r0
      r_load_2 r3
      n_ine r2, r2, r3
      b_if r2, done

      n_promote r2, r1, r1
      n_iinc r3, r3
      n_ine r2, r2, r3
      b_if r2, done

      r_load_int r1, r1
      n_eshl r0, r0, r1
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other = Rubinius::Type.coerce_to other, Integer, :to_int

    self >> -other if other < 0

    unless other.kind_of? Fixnum
      raise RangeError, "argument is out of range for a Fixnum"
    end

    self << other
  end

  def >>(other)
    Rubinius.asm do
      shr = new_label
      neg = new_label
      eint = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, neg
      goto eint

      neg.set!
      r_load_int r2, r1
      r_load_0 r3

      n_ige r3, r2, r3
      b_if r3, shr

      n_ineg r1, r2
      r_store_int r1, r1
      n_ishl_o r0, r0, r1
      r_ret r0

      shr.set!
      n_ishr_o r0, r0, r1
      r_ret r0

      eint.set!
      n_promote r2, r0, r0
      r_load_2 r3
      n_ine r2, r2, r3
      b_if r2, done

      n_promote r2, r1, r1
      n_iinc r3, r3
      n_ine r2, r2, r3
      b_if r2, done

      r_load_int r1, r1
      n_eshr r0, r0, r1
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    other = Rubinius::Type.coerce_to other, Integer, :to_int

    self << -other if other < 0

    unless other.kind_of? Fixnum
      raise RangeError, "argument is out of range for a Fixnum"
    end

    self >> other
  end

  def to_i
    self
  end

  alias_method :to_int, :to_i
  alias_method :truncate, :to_i
  alias_method :ceil, :to_i
  alias_method :floor, :to_i

  def chr(enc=undefined)
    if self < 0 || (self & 0xffff_ffff) != self
      raise RangeError, "#{self} is outside of the valid character range"
    end

    if undefined.equal? enc
      if 0xff < self
        enc = Encoding.default_internal
        if enc.nil?
          raise RangeError, "#{self} is outside of the valid character range"
        end
      elsif self < 0x80
        enc = Encoding::US_ASCII
      else
        enc = Encoding::ASCII_8BIT
      end
    else
      enc = Rubinius::Type.coerce_to_encoding enc
    end

    String.from_codepoint self, enc
  end

  def round(ndigits=undefined)
    return self if undefined.equal? ndigits

    if ndigits.kind_of? Numeric
      if ndigits > Fixnum::MAX or ndigits <= Fixnum::MIN
        raise RangeError, "precision is outside of the range of Fixnum"
      end
    end

    ndigits = Rubinius::Type.coerce_to ndigits, Integer, :to_int

    if ndigits > 0
      to_f
    elsif ndigits == 0
      self
    else
      ndigits = -ndigits

      # We want to return 0 if 10 ** ndigits / 2 > self.abs, or, taking
      # log_256 of both sides, if log_256(10 ** ndigits / 2) > self.size.
      # We have log_256(10) > 0.415241 and log_256(2) = 0.125, so:
      return 0 if 0.415241 * ndigits - 0.125 > size

      f = 10 ** ndigits

      if kind_of? Fixnum and f.kind_of? Fixnum
        x = self < 0 ? -self : self
        x = (x + f / 2) / f * f
        x = -x if self < 0
        return x
      end

      return 0 if f.kind_of? Float

      h = f / 2
      r = self % f
      n = self - r

      unless self < 0 ? r <= h : r < h
        n += f
      end

      n
    end
  end

  def gcd(other)
    raise TypeError, "Expected Integer but got #{other.class}" unless other.kind_of?(Integer)
    min = self.abs
    max = other.abs
    while min > 0
      tmp = min
      min = max % min
      max = tmp
    end
    max
  end

  def rationalize(eps = nil)
    Rational(self, 1)
  end

  def numerator
    self
  end

  def denominator
    1
  end

  def to_r
    Rational(self, 1)
  end

  def lcm(other)
    raise TypeError, "Expected Integer but got #{other.class}" unless other.kind_of?(Integer)
    if self.zero? or other.zero?
      0
    else
      (self.div(self.gcd(other)) * other).abs
    end
  end

  def gcdlcm(other)
    gcd = self.gcd(other)
    if self.zero? or other.zero?
      [gcd, 0]
    else
      [gcd, (self.div(gcd) * other).abs]
    end
  end

  def [](index)
    index = Rubinius::Type.coerce_to(index, Integer, :to_int)
    return 0 if index.is_a?(Bignum)
    index < 0 ? 0 : (self >> index) & 1
  end

  def next
    self + 1
  end

  alias_method :succ, :next

  def integer?
    true
  end

  def even?
    self & 1 == 0
  end

  def odd?
    self & 1 == 1
  end

  def ord
    self
  end

  def pred
    self - 1
  end

  def size
    Rubinius.asm do
      eint = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_self r0

      n_promote r1, r0, r0

      r_load_2 r2
      n_ieq r3, r1, r2
      b_if r3, eint

      n_iinc r2, r2
      n_ine r3, r1, r2
      b_if r3, done

      n_isize r0, r0
      goto val

      eint.set!
      n_esize r0, r0

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  def times
    return to_enum(:times) { self } unless block_given?

    i = 0
    while i < self
      yield i
      i += 1
    end
    self
  end

  def upto(val)
    return to_enum(:upto, val) { self <= val ? val - self + 1 : 0 } unless block_given?

    i = self
    while i <= val
      yield i
      i += 1
    end
    self
  end

  def downto(val)
    return to_enum(:downto, val) { self >= val ? self - val + 1 : 0 } unless block_given?

    i = self
    while i >= val
      yield i
      i -= 1
    end
    self
  end

  # conversions

  def coerce(other)
    Rubinius.asm do
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_m_binops r0, r1

      n_promote r2, r0, r1

      r_load_0 r3
      n_ieq r3, r3, r2
      b_if r3, done

      r_load_1 r3
      n_ine r3, r3, r2
      b_if r3, val

      r_store_float r0, r0
      r_store_float r1, r1

      val.set!
      r_store_stack r1
      r_store_stack r0
      make_array 2
      ret

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super other
  end

  def imaginary
    0
  end

  def to_f
    Rubinius.asm do
      eint = new_label
      done = new_label

      r0 = new_register
      r1 = new_register
      r2 = new_register
      r3 = new_register

      r_load_self r0

      n_promote r1, r0, r0

      r_load_2 r2
      n_ieq r3, r1, r2
      b_if r3, eint

      n_iinc r2, r2
      n_ine r3, r1, r2
      b_if r3, done

      n_iflt r0, r0
      r_store_float r0, r0
      r_ret r0

      eint.set!
      n_eflt r0, r0
      r_store_float r0, r0
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  def to_s(base=10)
    Rubinius.asm do
      int = new_label
      eint = new_label
      base = new_label
      val = new_label
      done = new_label

      r0 = new_register
      r1 = new_register

      r_load_m_binops r0, r1

      b_if_int r0, r1, int

      b_if_eint r0, r0, base
      goto done

      base.set!
      b_if_int r1, r1, eint
      goto done

      eint.set!
      n_estr r0, r0, r1
      goto val

      int.set!
      n_istr r0, r0, r1

      val.set!
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super base
  end

  # We do not alias this to #to_s in case someone overrides #to_s.
  def inspect
    Rubinius.asm do
      int = new_label
      eint = new_label
      done = new_label

      r0 = new_register
      r1 = new_register

      r_load_literal r1, 10

      r_load_self r0

      b_if_int r0, r0, int
      b_if_eint r0, r0, eint
      goto done

      int.set!
      n_istr r0, r0, r1
      r_ret r0

      eint.set!
      n_estr r0, r0, r1
      r_ret r0

      done.set!

      # TODO: teach the bytecode compiler better
      push_true
    end

    super
  end

  # predicates

  def zero?
    self == 0
  end

end