0

Inspired from this post, I wanted to generalize the problem. to check if given number m is integer power of number n.

Here is my first attempt and and as I tested it, everything is ok.

Then I attempted to write something different inspired from a response to the post on the link. Main idea is to check if logarithm of one number on base of another is integer or not. For this reason I used natural logarithm knowing that,
logab/logac =logcb

(my ruby version is 1.8.7)

def m_is_power_of_n(m,n)

    #false by definiton

    f1  = (n==0 and m!=0)
    f2 = (n==1 and m!=1)

    #true by definition

    t1 = m==n
    t2 = m==1

    if f1 or f2
        return false
    elsif t1 or t2
        return true
    else
        a = Math.log(m)/Math.log(n) 
        return a.to_i == a #updated after steenslag's comment
        #if a.to_i == a
        #    return true
        #else 
        #    return false
        #end
    end
end

I don't know what I am doing wrong because when I pass arguments (36,6), (125,5) it returns true as I expected. But for (216,6) or (25,5) it returns false.

P.S. btw, I am a ruby newbie, all criticisms about coding style are welcome :)

Community
  • 1
  • 1
marmeladze
  • 6,468
  • 3
  • 24
  • 45

1 Answers1

3

You have a precision problem, as you could see if you used irb

irb(main):001:0> Math.log(216)
=> 5.375278407684165
irb(main):002:0> Math.log(6)
=> 1.791759469228055
irb(main):003:0> Math.log(216)/Math.log(6)
=> 3.0000000000000004

And unfortunately 3.0000000000000004 isn't equal to 3.

You could possibly round the result...

a = (Math.log(m)/Math.log(n)).round(14)
SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53
  • it was one of my fears but now i just typed (ruby version 1.8.7) your 3rd expression and it spitted out 3.0. regardless of this result i think the problem is something like that. i'll now check rounding. – marmeladze Apr 18 '15 at 21:41
  • round(number) is ok for ruby 2.2 (checked on repl.it), but for 1.8.7 it raises `ArgumentError: wrong number of arguments (1 for 0)` . just round() without argument is a candidate to solve shown problems but this will cause another big errors like, (61, 6) also will evaluate true. – marmeladze Apr 18 '15 at 22:05
  • 1
    I still prefer your original code... and of course you can implement it as an integer method... `class Integer;def is_power_of(a_number); return true if self == 1;return false if self == 0; a_number = a_number / self while a_number % self == 0; a_number == 1;end;end` This would let you do `5.is_power_of 125` – SteveTurczyn Apr 18 '15 at 22:05
  • i also do prefer it. but what is problem with logarithms? especially on my ruby version. maybe my expectation from ruby for change of base is problematic. – marmeladze Apr 18 '15 at 22:17
  • 1
    Well, clearly there are improvements in later versions of ruby. If you could upgrade to 1.9, even, you would have the ability to pass an argument to the `#round` method. Under 1.8.7 you could approximate the round method with `a = (a * 10000000000000).to_i / 10000000000000.0 ; return a.to_i == a` – SteveTurczyn Apr 18 '15 at 22:25