ruby 创建一个方法来判断一个数是否是2的幂?

xpszyzbs  于 2023-03-12  发布在  Ruby
关注(0)|答案(9)|浏览(416)

如果num是2的幂,我用这段代码返回true

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)

但是我总是得到一个错误。我该如何修正和简化这个代码呢?

z9gpfhce

z9gpfhce1#

显然,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_length和Fixnum#[]:

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

“第四个,也许是最好的"

def po2?(n)
  return false if n <= 0
  while n.even?
    n /= 2
  end
  n == 1
end
po2?  0     #=> false
po2?  1     #=> true
po2? 32     #=> true
po2? 33     #=> false
0vvn1miw

0vvn1miw2#

试试看:

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

here解释得很好(对于C#,但@GregHewgill的解释在这里也适用)

11dmarpk

11dmarpk3#

我会使用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

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

ax6ht2ek

ax6ht2ek4#

另一个解决这个问题的方法是与这里的大多数答案相反--我们可以从数字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的幂。

k4emjkb1

k4emjkb15#

正如在上面的注解中指出的,您会得到错误,因为您试图在一个不可迭代的对象(一个int)上使用inject方法。

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

请评论任何改进,你可能会发现任何。

fxnxkyjh

fxnxkyjh6#

下面是另一个使用递归的解决方案:

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

gojuced77#

在我看来,最简单的--但可能有点长--方法就是这样编写这个递归方法:

def power_of_two?(number)
    continue = true
    if number == 1
        return true
    end
    if number % 2 != 0
        return false
    else
        while continue == true do
            if number.to_f / 2.0 == 2.0
                continue = false
                return true
            else
                if number % 2 != 0
                    continue = false 
                    return false
                else
                    number /= 2
                    continue = true
                end
            end
        end
    end
end

1是2的幂(2^0),因此它首先检查给定的数字是否为1。如果不是,则检查它是否为奇数,因为1是唯一一个2的幂的奇数。
如果是奇数,则返回false,并转到else语句,检查除以2的数是否为2,因为如果是2的幂,则显然是2的幂,这是一个浮点数,因为Ruby中的5/2将返回2。
如果为false,则再次检查数字是否为奇数--第一轮不需要,之后需要。如果数字不是奇数,则将数字除以2,然后再循环一次。
这将持续下去,直到程序通过得到2或任何奇数来解析自己,并分别返回true或false。

moiiocjp

moiiocjp8#

我在一个训练营应用程序准备中遇到了这个问题。我不是一个数学爱好者,不理解其中的一些方法,所以我想为像我这样的人提交一个常识性的方法。这需要很少的数学知识,除了知道一个数字的二次幂将是某个数字乘以自己的结果。

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

这个方法计数到从1开始的num变量,并且如果(序列中的任何一个数字乘以它自己)等于num &如果num不为0(下面将详细介绍),则返回真。
示例:数值= 9
返回true,方法运行结束。

倍方法需要大于0的整数,因此,由于#倍以“0”作为变量不做任何事情并且当在#倍迭代之外时返回假的事实,该边缘情况被“处理”。

jucafojl

jucafojl9#

def power_of_two?(num)
  num.to_s(2).scan(/1/).length == 1
end

相关问题