Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factorial and test unit for factorial #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

hemahg
Copy link

@hemahg hemahg commented Oct 3, 2019

No description provided.

return result
else
power = -1*power
for i in (1..power) do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you could have done:

1.0/pow(num, -power)

But that is fine ;)

class Power
def self.pow(num,power)
result = 1.0
if(power >=0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parenthesis are not mandatory

for i in (1..power) do
result = result*num
end
return result
Copy link

@hallelujah hallelujah Oct 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can return result at the end of the method

for i in (1..power) do
result = result*(1/num)
end
return result.round(9)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is acceptable for the purpose of the excercise

@n = @n - 1
end
result
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be wary of indentation, it makes the code more readable.
You probably want to setup your IDE with correctly.

That makes me think of a good read for start https://github.com/rubocop-hq/ruby-style-guide




class Facttest < Test::Unit::TestCase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow convention for file and directory namingnaming

@@ -0,0 +1,21 @@
require "test/unit"
require_relative "/home/hema/RoR-Learning-Path/Programming Foundations: Algorithms/Factorial-test/fact"
Copy link

@hallelujah hallelujah Oct 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not require_relative

Rubyists generally run test with include in load path option -I. e.g: ruby -Ilib:test test/my_example_test.rb

assert_equal(6, Fact.new(3).fact)
end

def test_Zero

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert_equal(1, Fact.new(0).fact)
end

def test_negative

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require 'first_project/power'

class PowerTest < TestBase
test 'powerofnumber' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the name is just a string, i think that it is easier to read like this: 😄

Suggested change
test 'powerofnumber' do
test 'power of number' do

And then when you run the test, it will convert it internally to power_of_number which is how we name methods in Ruby (this naming convention is called snake case)

def self.pow(num, power)
result = 1
if power >= 0
for i in (1..power) do
Copy link

@Martouta Martouta Oct 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I am gonna say in this comment, I don't know if it is appropiate or if it is too early (too difficult at this stage), so if you find it too hard right now, do not worry and just ignore this comment 😂

In Ruby we usually write this for i in (1..power) do like (1..power).each do |i| and what it does is: for the instance (1..power) of the class Range, call its instance method each and run the block after the do with the i as the parameter of the block.

Alternatively, as you do not mind about the index at all, you can also use the instance method times of the class Integer, which you can use when either you don't care about the value of the index, or when it can start by 0.

So it would be:

power.times { result *= num }

Considering that { ... } is the same as do ... end 😄 .

You can also use inject of an Enumerable (which is mostly any object that can be iterated, like a Range or an Array for example), and then you do not need the result variable and it is shorter 😄 Although it is too inneficient for this and I wouldn't recommend it, but since this is for the sake of learning, it would be:

def self.pow(num, power)
  if power >= 0
    ([num] * power).inject(1) { |n, result| result * n } # Or even: ([num] * power).inject(:*) || 1
  else
    1.0 / pow(num, -power)
  end
end

What ([num] * power).inject(1) { |n, result| result * n } does is, first make an array of power elements, all of them containing num, and then iterate all of them, with a variable called result starting by 1, and for each iteration of the array save in that variable the value of result * num, which is what returns at the end.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there could be also a recursive version of this method, which in code is usually simpler but you also need to check to what it does with the stack of memory 😄 This version would be:

def self.pow(num, power)
  if power == 0
    1
  elsif power > 0
    num * pow(num, power - 1)
  else # power < 0
    1.0 / pow(num, -power)
  end
end

And there are probably more efficient versions but for now this is enough 😄

@@ -0,0 +1,15 @@
module Hema
class Power
Copy link

@Martouta Martouta Oct 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We spoke in private before but I rather put it here as well.
We don't usually create a class if we don't expect it to be ever instantiate it and for that we usually just make a module instead. Like this:

module Hema
  module Power
    def pow(...)
      ...
    end
  end
end

And from outside called like: Hema::Power.pow(...)

Copy link

@hallelujah hallelujah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation is good.

Now all comments are about Styling and using Ruby Core Library methods

end

def fact
if @n == 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to avoid many nested if for learning you have https://rubystyle.guide

You can also use rubocop to tell you what is bad styling in your code https://github.com/rubocop-hq/rubocop

raise 'negatives are not acceptable'
else
result = 1
while @n > 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stateed by @Martouta, when you have Enumerable, try to read the docs and use some of the methods of this module.

Try to understand this simpler version is:

(1..n).inject(&:*)


def test_negative
Factorial_test::Fact.new(-5).fact
assert_raise do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not work as you do not execute nothing inside the block.

class PowerTest < TestBase
test 'powerofnumber' do
assert_equal 4, Hema::Power.pow(2, 2)
assert_equal 1, Hema::Power.pow(2.0, 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are formatting/styling issues, see https://rubystyle.guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants