-2

I'm trying to check whether a number is a perfect square.

This is my code:

def is_square(x)
  return true if
  math.sqrt(x).is_a? Integer
end

Any idea why it doesn't work?

sawa
  • 165,429
  • 45
  • 277
  • 381
Sarah
  • 86
  • 2
  • 4
  • Possible duplicate of [Optimization for finding perfect-square algorithm](https://stackoverflow.com/questions/36896936/optimization-for-finding-perfect-square-algorithm) – cnnr May 28 '18 at 13:05
  • `Math` should be capitalized, like `return true if Math.sqrt(x).is_a?(Integer`) . Also the name of the method could better to be `is_square?(x)` – Xullnn May 28 '18 at 13:08
  • Thank you. I have just done that but it's still returning the following error messages:# main.rb:4:in `is_square' main.rb:11:in `block (2 levels) in ' /runner/frameworks/ruby/cw-2.rb:180:in `wrap_error' /runner/frameworks/ruby/cw-2.rb:72:in `it' /runner/frameworks/ruby/cw-2.rb:206:in `it' main.rb:10:in `block in ' /runner/frameworks/ruby/cw-2.rb:55:in `block in describe' /runner/frameworks/ruby/cw-2.rb:46:in `measure' /runner/frameworks/ruby/cw-2.rb:51:in `describe' /runner/frameworks/ruby/cw-2.rb:202:in `describe' main.rb:9:in ` ' – Sarah May 28 '18 at 13:11
  • What are you using to run the program? – Aaron Christiansen May 28 '18 at 13:13
  • It's on codewars. It's still full of errors even when I divide by 1 to avoid getting a float... Don't worry, your answer was still very useful and helped me to learn more about coding! – Sarah May 28 '18 at 13:22
  • What do you mean "isn't working"? – Sergio Tulentsev May 28 '18 at 15:19
  • Can you explain what "it doesn't work" means? Do you get an error? If yes, what is the error? Do you get a wrong result? If yes, what is the result you get and what is the result you expect (and why do you expect to get that result)? Did you read what the documentation of `Math::sqrt` says about what it returns? – Jörg W Mittag May 29 '18 at 16:03

5 Answers5

6
  1. You mispelled Math, which is constant holding module designed for mathematic operations.
  2. Math.sqrt(9) also returns float, so this isn't gonna work either. But you can check the remainder of division by 1.
  3. Apart from this, the style in which you wrote this method is really bad, it can be written much better.

To summarize, I would do something like this:

def is_square?(x)
  (Math.sqrt(x) % 1).zero?
end
Marek Lipka
  • 50,622
  • 7
  • 87
  • 91
  • Thank you. I have only recently started learning, hence the style errors. – Sarah May 28 '18 at 13:16
  • The original version of the [Pickaxe Book](https://pragprog.com/book/ruby4/programming-ruby-1-9-2-0) is available [for free](http://ruby-doc.com/docs/ProgrammingRuby/) and is a great introduction to the Ruby language and its style conventions. – tadman May 28 '18 at 16:35
3

The result is aways a float:

Math.sqrt(4)
# => 2.0

Math.sqrt(4).class
#  => Float

You need to check if the result is a number without decimal points:

def is_square(x)
  Math.sqrt(x) % 1 == 0
end
koffeinfrei
  • 1,985
  • 13
  • 19
1

First, you need to capitalise math to Math.

The other problem with this code is the return value of Math.sqrt. Suppose you supply 4 as the value of x. Math.sqrt always returns a Float (a decimal), even if that Float happens to be a round number, so the result would be 2.0. As far as Ruby is concerned, and most programming languages for that matter, 2.0 isn't an Integer. It's still a Float, just one which doesn't have any decimal portion.

The easiest way to check if a Float is an integer is to mod it by 1 (that is, divide it by 1 and get the remainder), which may be done using %, and then check that this remainder is 0.

def is_square(x)
  return true if Math.sqrt(x) % 1 == 0
end

This function still isn't perfect though; it returns true for a square and nil for a non-square. It'd make more sense for it to return false for a non-square instead.

This can be done by removing the if, and simply returning the result of the conditional. Also, return in Ruby isn't required for the last statement of a block.

def is_square(x)
  Math.sqrt(x) % 1 == 0
end
Aaron Christiansen
  • 11,584
  • 5
  • 52
  • 78
1

Since Ruby 2.5 the Integer class has sqrt , which returns the integer square root.

def is_square?(x)
  Integer.sqrt(x) ** 2  == x
end
steenslag
  • 79,051
  • 16
  • 138
  • 171
0

The result of Math#sqrt will never be an integer type, even for perfect squares. In general, type checks are not very helpful in Ruby.

Instead, there are a couple strategies you can use to determine if a number is integer in Ruby.

Compare against coerced value:

x == x.to_int

Check if the denominator is 1:

x.denominator == 1

Check if the remainder modulo 1 is 0:

x % 1 == 0

As an aside, idiomatic Ruby also doesn't use prefixes like is_, but instead adds a suffix question mark to predicate methods:

def perfect_square?(x)
  # Implementation
end
Drenmi
  • 8,492
  • 4
  • 42
  • 51