Возведение в степень не работает

Я новичок в программировании, особенно в Ruby, поэтому я делал несколько простых проектов. У меня есть этот код, и, насколько мне известно, он должен работать, но дает результаты, которых я не ожидаю.

Программа принимает a и B и возвращает a^b. Я сделал это в качестве упражнения по программированию, поэтому я просто не сошел с ума.

class Exponate
  attr_accessor :args

  def initialize args = {}
    @args = args
    @ans = nil
  end

  def index
    @args[:b].times {
      @ans = @args[:a] * @args[:a]
    }
    puts @ans
  end
end

e = Exponate.new(:a => 32, :b => 6)
e.index

e.args[:a] = 5
e.index

Возвращает

1024     # Should be 1_073_741_824
25       # Should be 15_625

Но они точно не те


person Soviet Ketchup    schedule 13.02.2016    source источник
comment
Почему бы не просто @args[:a] ** (@args[:b] + 1)?   -  person spickermann    schedule 13.02.2016
comment
@spickermann Потому что я хотел сделать это вручную, как упражнение по программированию.   -  person Soviet Ketchup    schedule 13.02.2016
comment
Вы должны улучшить свой вопрос, описав, что вы хотите, чтобы программа делала, иначе она будет закрыта.   -  person Pedro Rolo    schedule 13.02.2016


Ответы (2)


Вы можете написать так:

class Exponate
  attr_accessor :args, :ans

  def initialize args = {}
    @args = args
  end

  def index
    @ans = 1 # multiplication will start from 1
    @args[:b].times {
      @ans *=  @args[:a] #same as @ans = @ans * @args[:a]
    }
    puts @ans
  end
end
person Ilya    schedule 13.02.2016
comment
Спасибо! Единственное, что я изменил после этого, это перемещение @ans = 1 из инициализации в индекс, потому что иначе он не сбрасывается. - person Soviet Ketchup; 13.02.2016

@ans = @args[:a] * @args[:a] вернет одно и то же значение, независимо от того, сколько раз вызывалось, вам нужно каким-то образом сослаться на переменную-аккумулятор, чтобы использовать цикл.

Использование переменной экземпляра для локального кажется неправильным — их время жизни больше, поэтому после выхода из метода их нельзя собрать, если на весь объект все еще где-то ссылаются. Также @ более подвержены ошибкам - если вы сделаете опечатку (например - @asn вместо @ans), вы получите nil вместо NameError, это может быть сложнее отладить, поэтому лучше писать так:

def index
  ans = 1
  args[:b].times {
    ans *= args[:a]
  }
  puts ans
end

Для циклов с аккумулятором в ruby ​​лучше использовать Enumerable#inject:

@ans = @args[:b].times.inject(1){|acc,v| acc * @args[:a]}

таким образом меньше шансов забыть инициализацию.

person Vasfed    schedule 13.02.2016