创建一个方法来查找数字是否为2的幂?

时间:2015-07-22 21:19:57

标签: ruby methods fixnum

如果true是2的幂,我会让此代码返回num

def is_power_of_two?(num)
  result = num.inject(0) {|n1, n2| n2 ** n1}
  if result == num
    true
  else
    false
  end
end

p is_power_of_two?(16)

我不断收到错误。我该如何修复和简化此代码?

8 个答案:

答案 0 :(得分:5)

显然,n是一个非负整数。

<强>代码

def po2?(n)
  n.to_s(2).count('1') == 1
end

<强>实施例

po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false

<强>解释

Fixnum#to_s提供给定基数的整数(接收器)的字符串表示。方法的参数(默认为10)是基础。例如:

16.to_s     #=> "16" 
16.to_s(8)  #=> "20" 
16.to_s(16) #=> "10"
15.to_s(16) #=>  "f"

这是我们感兴趣的基础2.对于2的权力:

 1.to_s(2)  #=>      "1" 
 2.to_s(2)  #=>     "10" 
 4.to_s(2)  #=>    "100" 
 8.to_s(2)  #=>   "1000"
16.to_s(2)  #=>  "10000"

对于一些不是2的幂的自然数:

 3.to_s(2)  #=>    "11" 
 5.to_s(2)  #=>   "101" 
11.to_s(2)  #=>  "1011" 

因此,我们希望匹配包含一个1的二进制字符串。

另一种方式

R = /
    \A      # match beginning of string ("anchor")
    10*     # match 1 followed by zero or more zeroes
    \z      # match end of string ("anchor")
    /x      # free-spacing regex definition mode

def po2?(n)
  (n.to_s(2) =~ R) ? true : false
end

po2?(4)  #=> true
po2?(5)  #=> false

一条路

这使用Fixnum#bit_lengthFixnum#[]

def po2?(n)
  m = n.bit_length-1
  n[m] == 1 and m.times.all? { |i| n[i].zero? }
end

po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false

答案 1 :(得分:4)

尝试:

def is_power_of_two?(num)
  num != 0 && (num & (num - 1)) == 0
end

很好地解释了here(对于C#,但@ GregHewgill的解释也适用于此处)

答案 2 :(得分:1)

我会使用Ruby的Math模块做这样的事情。

def power_of_two?(n)
  Math.log2(n) % 1 == 0
end

或者,如果你想变得很酷:

def power_of_two?(n)
  (Math.log2(n) % 1).zero?
end

一些IRB输出:

2.1.0 :004 > power_of_two?(2)
 => true
2.1.0 :005 > power_of_two?(32768)
 => true
2.1.0 :006 > power_of_two?(65536)
 => true

此方法假定输入为正整数。

Source

答案 3 :(得分:0)

正如上面的评论中指出的那样,您遇到了错误,因为您尝试在非迭代(int)上使用inject方法。这是使用建议的log2

的解决方案
def is_power_of_two?(num)
  result = Math.log2(num)
  result == Integer(result)
end

注意:接近二进制文件的数字很大(如2 ^ 64 - 1)会失败。一个万无一失的版本(但速度较慢)将是:

def is_power_of_two?(num)
  while (num % 2 == 0 and num != 0)
    num /= 2
  end
  num == 1
end

请评论您可能找到的任何改进。

答案 4 :(得分:0)

这是另一种使用递归的解决方案:

def power_of_2?(number)
 return true if number == 1
 return false if number == 0 || number % 2 != 0
 power_of_2?(number / 2)
end

答案 5 :(得分:0)

在我看来,最简单的 - 但也许有点长 - 做你需要做的事就是这样写这个递归方法:

<asp:GridView ID="GridView12" DataKeyNames="DealId" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1">
                        <Columns>
                            <asp:CommandField ShowSelectButton="True" ShowHeader="False" />
                            <asp:BoundField DataField="DealId" ItemStyle-CssClass="gv-class" SortExpression="DealId" Visible="true" />
                            <asp:BoundField DataField="DealName" ItemStyle-CssClass="gv-class" SortExpression="DealName" />
                            <asp:BoundField DataField="DealDescription" ItemStyle-CssClass="gv-class" SortExpression="DealDescription" />
                            <asp:BoundField DataField="DealLocation" ItemStyle-CssClass="gv-class" SortExpression="DealLocation" />
                            <asp:BoundField DataField="DealPrice" ItemStyle-CssClass="gv-class" SortExpression="DealPrice" />
                            <asp:BoundField DataField="ImagePath" ItemStyle-CssClass="gv-class" SortExpression="ImagePath" />
                        </Columns>
                    </asp:GridView>
                </div>
                <div class="col-md-8">
                    <asp:DetailsView ID="DetailsView1" CssClass="image-class" runat="server" Height="50px" AutoGenerateRows="False" DataSourceID="SqlDataSource2">
                        <Fields>
                            <asp:ImageField DataImageUrlField="ImagePath" ItemStyle-CssClass="dv-img" SortExpression="ImagePath"/>
                            <asp:BoundField DataField="DealId" ItemStyle-CssClass="dv-1 float" SortExpression="DealId" Visible="false"/>
                            <asp:BoundField DataField="DealName" ItemStyle-CssClass="dv-2 float" SortExpression="DealName" />
                            <asp:BoundField DataFie`enter code here`ld="DealDescription" ItemStyle-CssClass="dv-3 float" SortExpression="DealDescription" />
                            <asp:BoundField DataField="DealLocation" ItemStyle-CssClass="dv-4 float" SortExpression="DealLocation" />
                            <asp:BoundField DataField="DealPrice" ItemStyle-CssClass="dv-5 float" SortExpression="DealPrice" />                                
                        </Fields>
                    </asp:DetailsView>

一个是2的幂(2 ^ 0),因此它首先检查给定的数字是否为1.如果不是,则检查它是否为奇数,因为1是唯一的奇数是2的幂。

如果是奇数,则返回false并继续执行else语句。它将检查除以2的数字是否为2,因为它显然是2的幂。它将它作为浮点数,因为Ruby中的5/2将返回2.

如果这是假的,那么它会再次检查数字是否为奇数 - 在第一轮是不必要的,之后是必要的。如果数字不是奇数,它将数字除以2,然后再次循环。

这将持续到程序通过获取2或任何奇数来解析自身,并分别返回true或false。

答案 6 :(得分:0)

我在bootcamp应用程序准备中遇到了这个。我不是一个数学家,也不了解其中的一些方法,所以我想为像我这样的人提交常识。这需要很少的数学知识,除了知道第二个幂的数字将是某个数字乘以其自身的结果。

def is_power_of_two?(num)
  num.times  {|n| return true if (n+1) * (n+1) == num}
  false
end

此方法从1开始计数num变量,如果(序列中的任何数字乘以其自身)等于num&amp;,则返回true。如果num不是0(下面有更多内容)。

例如: num = 9

1 * 1 == 9 #=> false
2 * 2 == 9 #=> false
3 * 3 == 9 #=> true 

返回true并且方法已完成运行。

#times方法需要一个整数&gt; 0,所以这个边缘情况是“处理”的,因为#times不做任何事情,“0”作为变量,并在#times迭代之外返回false。

答案 7 :(得分:0)

解决此问题的另一种方法是与此处的大多数答案相反—我们可以使用数字1来开始计算数字是否为2的幂。像这样:

def power_of_two?(num)
  product = 1

  while product < num
    product *= 2
  end
  product == num
end

我们从1开始。然后将1乘以2,并继续乘以2,直到乘积大于numproduct < num)。一旦达到该条件,我们将停止,退出循环,并检查其是否等于numproduct == num)。如果是,则num是2的幂。