4

I'm trying to use Ruby's inject to sum an array representing a finite continued fraction, where

[a, b, c, d, e, ... , x] = a + 1/(b + 1/(c + 1/(d + 1/(e + ... 1/x)...)))

I can't figure out how to get the proper nested evaluation to return the correct value using inject.

Instead, what I've written just returns the flat sum of the terms rather than a nested sum. For example,

total = [0, 2, 1, 12, 8].inject do |sum,x|
  sum = sum + Rational(1,x)
end
puts total
#=>  41/24

That is, 0 + 1/2 + 1/1 + 1/12 + 1/8 #=> 41/24 instead of 0 + 1/(2 + 1/(1 + 1/(12+1/8))) #=> 105/307, which is the correct value.

Is it possible to compute this type of sum using the inject method?

If not, how can I compute it correctly?

regulus
  • 939
  • 3
  • 13
  • 21
  • 1
    When using `inject` (aka `reduce`), the block variable that is the accumulator (generally referred to as the *memo*)--here `sum`--is assigned to the result of the block calculation at each step. You therefore can simplify `sum = sum + Rational(1,x)` to `sum + Rational(1,x)`. – Cary Swoveland Jul 06 '19 at 22:06
  • This is neither here nor there, but a more compact way to write `Rational(1, x)` is `1r/x`. – Jordan Running Jul 08 '19 at 16:08

1 Answers1

5
arr = [0, 2, 1, 12, 8]

arr.reverse.reduce { |tot, n| n + Rational(1, tot) }
  #=> 105/307

The steps:

a = arr.reverse
  #=> [8, 12, 1, 2, 0] 
b = a.reduce do |tot ,n|
  puts "tot=#{tot}, n=#{n}"
  (n + Rational(1, tot)).tap { |r| puts "  tot=#{r}" }
end
  #=> (105/307) 

This prints:

tot=8, n=12
  tot=97/8
tot=97/8, n=1
  tot=105/97
tot=105/97, n=2
  tot=307/105
tot=307/105, n=0
  tot=105/307

Alternatively, recursion could be used.

def recurse(arr)
  arr.size == 1 ? arr.first : arr.first + Rational(1, recurse(arr.drop(1)))
end

recurse arr
  #=> (105/307)
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100