2

I have tried to create a method in Ruby which returns true if number is included fibonacci-sequence or false if it's not.

I think I got a problem when I return true or false.

Could anybody tell me why the first code doesn't work please?

def is_fibonacci?(num, array=[0,1])

  n = array.length - 1

  if array[n] > num
    array.include?(num) ? true : false
  end

  array << array[n] + array[n-1]
  is_fibonacci?(num, array)

end

When I run this code, I got this error message.

=>filename.rb:36:in `include?': Interrupt

def is_fibonacci?(num, array=[0,1])
  n = array.length - 1

  if array[n] > num
    if array.include?(num)
        return true
    else
        return false
    end
  end

  array << array[n] + array[n-1]
  is_fibonacci?(num, array)

end

Second code worked.

Why can't I use

array.include?(num) ? true : false 

in the code?

Thank you for helping.

jww
  • 97,681
  • 90
  • 411
  • 885
  • def fibonacci( n ) return n if n <= 1 fibonacci( n - 1 ) + fibonacci( n - 2 ) end puts fibonacci( 10 ) # => 55 – Santhucool Apr 15 '15 at 06:27
  • 2
    Just a short note on conding style: `array.include?(num)` already returns `true` or `false`. You can replace the whole `if ... else ... end` block with just `return array.include?(num)` – spickermann Apr 15 '15 at 06:41

6 Answers6

2

Shivam already gave an good answer to the question why your first version does not work.

I just want to note that there is no reason to keep all calculated fibonacci numbers in the array. That is a waste of space and probably a bit inefficient. Therefore you could simplify your method to:

def fibonacci?(number)
  fibos = [0, 1]
  fibos << (fibos.shift + fibos.last) while fibos.last < number
  fibos.include?(number)
end
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • creating lots of temp arrays is not super-efficient either :) – Sergio Tulentsev Apr 15 '15 at 07:09
  • @SergioTulentsev: You are right. Do you like this better? – spickermann Apr 15 '15 at 07:14
  • yeah, this is better, but: 1) you don't recurse (which is kinda the requirement, I think) 2) because of that you don't need the array in the signature (or even you don't need it at all). Something like this is even better: http://pastebin.com/1ew7Tktp – Sergio Tulentsev Apr 15 '15 at 07:18
  • I like your pastebin example. I am not sure about the recursion. Because this is a really bad example for recusion, because it makes the problem bigger in each recursion instead not smaller. Therefore recursion is a bad choice to solve the problem. If the recursion is requirement because it is a homework exercise, then I don't care... – spickermann Apr 15 '15 at 07:28
  • BTW, I agree that recursion should not be used here (if we're being practical). Or even loop, for that matter. There's a O(1) formula for calculating Nth fibonacci term. So we can use that and a binary search, I think. – Sergio Tulentsev Apr 15 '15 at 07:35
  • There aren't many good examples to teach recursion. I can't think of one off the top of my head. – Sergio Tulentsev Apr 15 '15 at 07:37
  • 1
    Some sorting algorithms like Merge or Quicksort are great examples. – spickermann Apr 15 '15 at 07:41
  • But sorting is way more complicated than fibonacci :) – Sergio Tulentsev Apr 15 '15 at 08:27
  • Maybe some tree-walking examples. Like turning AST into bytecode or whatever :) – Sergio Tulentsev Apr 15 '15 at 08:28
  • @SergioTulentsev The complexity of more realistic examples is why professors start off with toy examples like Fibonacci, factorials, and integer exponentiation, and towers of Hanoi. – pjs Apr 15 '15 at 15:19
  • @pjs: I understand. But students not always understand that using recursion _here_ is a bad idea. – Sergio Tulentsev Apr 15 '15 at 16:06
1

The reason array.include?(num) ? true : false does not work is because you have no return statement. Change it to return array.include?(num) ? true : false. WIthout it will just call another level of the recursion algorithm and in the end run too deep into into the stack.

And just as a bonus, here is the famous one-liner using a hash:

fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }

p fibonacci[2]  # => 1
p fibonacci[23] # => 28657
matthewdu
  • 43
  • 4
hirolau
  • 13,451
  • 8
  • 35
  • 47
  • 2
    Not to mention you should never use the pattern `boolean ? true : false` as the Boolean can speak for itself. – vgoff Apr 15 '15 at 20:28
  • Without use of memoization your algorithm complexity is exponential, do you really need that? – Anatoly Oct 03 '15 at 23:35
1

Why can't I use array.include?(num) ? true : false

Syntactically there is nothing wrong in this statement and it should work fine. (it may return SystemStackError: stack level too deep though in context of your code as you are not returning any value).

Here is an example:

array = [0,1]
num = 1
array.include?(num) ? true : false
# => true
num = 3
array.include?(num) ? true : false
# => false

However this is horrible code. Official documentation for .include? clearly states:

Returns true if the given object is present in self (that is, if any object == anObject), false otherwise.

Which means:

num = 1
array.include?(num)
# => true
num = 3
array.include?(num)
# => false

Again you are repeating the same mistake in the following code:

 if array.include?(num)
    return true
 else
    return false
 end

All of the above code can be replaced with just one line:

return array.include?(num)
spickermann
  • 100,941
  • 9
  • 101
  • 131
shivam
  • 16,048
  • 3
  • 56
  • 71
1

In your first version, the block

if array[n] > num
  array.include?(num) ? true : false
end

is syntactically correct (although nasty), but semantically incorrect for your program because you don't return the result. You can either add an explicit return on that statement, or make the rest of your program an else clause. The following version works because by default Ruby returns the result on the last statement executed and only one branch of the if/else gets evaluated:

def is_fibonacci?(num, array=[0,1])
  n = array.length - 1
  if array[n] > num
    array.include?(num)
  else
    array << array[n] + array[n-1]
    is_fibonacci?(num, array)
  end
end
pjs
  • 18,696
  • 4
  • 27
  • 56
0

Using the hash concept by @hirolau we can do this in two lines.

def fib?(n)
  @fibonacci ||= Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }
  (0..n+1).any? { |x| @fibonacci[x] == n }
end
Jkarayusuf
  • 361
  • 1
  • 6
0

Fibonacci numbers algorithm can be done two ways: with and w/o recursion. Recursion version must have a memoization implemented to avoid exponential complexity of algorithm.

Variant 1:

class Fibonacci
  def initialize(num)
    @num = num
    @array = [0,1]
  end

  def process
    return @num if [0,1].include?(@num)
    2.upto(@num).each do |i|
      @array[i] = @array[i-1] + @array[i-2]
    end
    @array[@num]
  end
end

Variant 2:

class FibonacciMemoizedRecursion
  def initialize(num)
    @num = num
    @memo = {0 => 0, 1 => 1, 2 => 1}
  end

  def process
    recursion(@num)
  end

  private

  def recursion(a)
    return @memo[a] if @memo.include?(a)
    @memo[a] = recursion(a-1) + recursion(a-2)
  end
end

To test we can use MiniTest library:

require 'minitest/autorun'

class FibonacciTest < Minitest::Unit::TestCase
  def test_process_1
    assert_equal 0, Fibonacci.new(0).process
  end

  def test_process_2
    assert_equal 1, Fibonacci.new(1).process
  end

  def test_process_3
    assert_equal 1, Fibonacci.new(2).process
  end

  def test_process_4
    assert_equal 2, Fibonacci.new(3).process
  end

  def test_process_5
    assert_equal 3, Fibonacci.new(4).process
  end

  def test_process_6
    assert_equal 5, Fibonacci.new(5).process
  end

  def test_process_7
    assert_equal 8, Fibonacci.new(6).process
  end

  def test_process_8
    assert_equal 13, Fibonacci.new(7).process
  end
end
Anatoly
  • 15,298
  • 5
  • 53
  • 77