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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.