コマンドラインの数が2の累乗であることを確認してください。

コマンドラインの数が2の累乗であることを確認してください。

コマンドラインに入力された数字が2の累乗であることを確認するbashスクリプトを作成することはできません。

入力する

# ./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の累乗であることを確認するための良い近道があります。

0b100000そのような数字が2進数で表される場合、数字32のように1の後に0が続く文字列になります。そこから1を引くと0があるところは1になり、0があるところは0になります。たとえば、0b011111数字31は32 - 1です。 2つをビット単位でANDすると0になります。この属性は、2の累乗(および0)の数値にのみ有効です。

だから:

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

または、数字の8進数表現を確認してください。

isPowerOf2() {
    local octal=$(printf %o "$1" 2>/dev/null) && 
      [[ $octal -eq 4 || $octal =~ ^[12]0*$ ]]
}

それともアイク多分

$ 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'; }

関連情報