我无法制作一个 bash 脚本来检查命令行中的输入数字是否为 2 的幂
输入
# ./pow2script.sh xyzdf 4 8 12 -2 USAD
期望的输出:期望的输出应该位于单独的行上
4
8
因为只有4是2^2,8是2^3
pow2script.sh 的内容
#!/bin/bash
function is_power_of_two () {
declare -i n=$1
(( n > 0 && (n & (n - 1)) == 0 ))
}
for number; do
if is_power_of_two "$number"; then
printf "%d\n" "$number"
fi
done
答案1
有一个很好的快捷方式可以检查一个数字是否是 2 的幂。
如果用二进制表示这样一个数字,它将是一个 1 后跟一串零,例如0b100000
数字 32。如果从中减去 1,您将在有零的地方得到 1,在有零的地方得到一个零。你有 1,例如0b011111
数字 31,它是 32 - 1。如果你对这两个进行按位与运算,你会得到一个零。该属性仅对二(和零)的幂的数字有效。
所以:
function is_power_of_two () {
declare -i n=$1
(( n > 0 && (n & (n - 1)) == 0 ))
}
将其用作:
for number; do
if is_power_of_two "$number"; then
printf "%d\n" "$number"
fi
done
以及执行输出:
$ ./power2.sh 1 2 3 4 5 7 8 9 31 32 33 -2
1
2
4
8
32
答案2
该数字是 2 的幂,如果汉明重量正好是 1。
计算一个数字的汉明权重与计算其二进制表示中 1 的数量相同。
以下是bash
执行此操作的简短脚本:
#!/bin/bash
# loop over all numbers on the command line
# note: we don't verify that these are in fact numbers
for number do
w=0 # Hamming weight (count of bits that are 1)
n=$number # work on $n to save $number for later
# test the last bit of the number, and right-shift once
# repeat until number is zero
while (( n > 0 )); do
if (( (n & 1) == 1 )); then
# last bit was 1, count it
w=$(( w + 1 ))
fi
if (( w > 1 )); then
# early bail-out: not a power of 2
break
fi
# right-shift number
n=$(( n >> 1 ))
done
if (( w == 1 )); then
# this was a power of 2
printf '%d\n' "$number"
fi
done
测试:
$ bash script.sh xyzdf 4 8 12 -2 USAD
4
8
注意:有更有效的方法可以做到这一点,并且bash
是特别语言选择不好。
因为它在短时间内出现了几次(这似乎是一项家庭作业或其他类型的练习):
1
如果输入中出现数字,我不会修改此代码以跳过该数字。- 我不会让它以任何形式输出数字之和。
- 除了评论中已经完成的内容之外,我不会进一步描述该算法。
答案3
另一种纯粹的 bash 方法
isPowerOf2 () {
local n=$1 i=0
for ((; n>1; n/=2, i++)); do :; done
(($1 - (2 ** $i) == 0))
}
和
$ for n in {1..17}; do isPowerOf2 $n && echo $n; done
1
2
4
8
16
或者查看数字的八进制表示形式:
isPowerOf2() {
local octal=$(printf %o "$1" 2>/dev/null) &&
[[ $octal -eq 4 || $octal =~ ^[12]0*$ ]]
}
或者 awk 也许
$ seq 17 | awk '{lg = log($1) / log(2)} lg == int(lg)'
1
2
4
8
16
答案4
$ is_power_of_two(){ printf '%x' "$1" | grep -q '^[1248]0*$'; }
$ powers_of_two(){ printf '%#x\n' "$@" | grep '^0x[1248]0*$' | xargs -I@ printf '%d\n' @; }
$ powers_of_two `seq 1 1000000`
1
2
4
8
16
32
64
128
...
在某些系统上(例如 busybox)xargs
不支持标准-I
选项,但支持 GNU -r
(如果为空则不运行)选项:
powers_of_two(){ test "$1" && printf '%#x\n' "$@" | grep '^0x[1248]0*$' | xargs -r printf '%d\n'; }