0

I come from a JavaScript background and wrote this similar to how I would in javascript. I am writing it in Ruby. This is a codewars exercise. n being 0 and 1 returns 0.00 and 1.00 as expected. Every other positive natural number returns 0.

# Task:
# Your task is to write a function which returns the sum of following series upto nth term(parameter).
# Series: 1 + 1/4 + 1/7 + 1/10 + 1/13 + 1/16 +...


# Rules:
# You need to round the answer to 2 decimal places and return it as String.
# If the given value is 0 then it should return 0.00
# You will only be given Natural Numbers as arguments.

# Examples:
# SeriesSum(1) => 1 = "1.00"
# SeriesSum(2) => 1 + 1/4 = "1.25"
# SeriesSum(5) => 1 + 1/4 + 1/7 + 1/10 + 1/13 = "1.57"


def series_sum(n)
    sum = 0
    if n == 0
        return 0.00
    elsif n == 1
        return 1.00
    else 
        n.times do |i|
            if i == 1 
                sum += 1
                break
            end 
            sum += 1/( 1 + (3 * (i - 1)) )
        end
    end
    return sum 
end

puts series_sum(0)
puts series_sum(1)
puts series_sum(2)
puts series_sum(4)
puts series_sum(5)

3 Answers 3

2

A couple of things to note: - Ruby has reduce method that can sum up a list of numbers: https://apidock.com/ruby/Enumerable/reduce - You don't need to explicitly return from your method. Ruby automatically returns the last statement in your method.

I've modified your solution, and this should work:

def series_sum(n)
  if n > 1
    sum = (1..n).inject { |sum, i| sum + (1/(1.to_f + (3 * (i - 1)))) }
  else
    sum = n
  end
  '%.2f' % sum
end

When you are expecting a decimal number in a division, always make sure that either the numerator or the denominator is in float, hence the reason for the 1.to_f. '%.2f' is a string format to ensure the final answer is returned in 2 decimal places.

Sign up to request clarification or add additional context in comments.

3 Comments

If you change inject to inject(0), you can do away with the if/else and turn it into a one-liner: '%.2f' % (1..n).inject(0) { |sum, i| sum + (1/(1.to_f + (3 * (i - 1)))) }
I was trying to make it as readable as possible considering the fact that the person asking the question is a beginner.
I doubt that putting (0) alters the readability by much. ;)
1

There are two parts to this question.

  1. How to display an operation's result as a float value?

    1/2 # this will give 0
    1.0/2 # this will give 0.5
    
  2. How to limit a float value to 2 decimal places?
    You can use the round function
     22.0/7 # this will give pi value - 3.142857142857143
     (22.0/7).round(2) # this will give 3.14
    
    The two answers above can be combined to get your answer. I would leave it as an exercise for you to come up with the exact code to solve your problem.

Comments

0
def series_sum(n)
  return "0.00" if n.zero?
  sprintf("%.2f", (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2))
end

series_sum(0) #=> "0.00" 
series_sum(1) #=> "1.00" 
series_sum(2) #=> "1.25" 
series_sum(3) #=> "1.39"
series_sum(4) #=> "1.49" 
series_sum(5) #=> "1.57" 

See Kernel#sprintf. One could alternatively use String%, which shares sprintf's formatting directives:

"%.2f" % (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2)

I am not aware of the existence of a closed-form expression for this partial sum. Though not relevant to the question, this partial sum can be shown to be divergent.

1 Comment

Thank you, I'm new to Ruby but I cannot wait till this efficient. Nice!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.