명령줄의 숫자가 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그러한 숫자가 이진수로 표현된다면 숫자 32 와 같이 1 다음에 0이 오는 문자열이 됩니다 . 거기에서 1을 빼면 0이 있는 곳은 1이 되고, 0이 있는 곳은 0이 됩니다. 예를 들어 0b011111숫자 31은 32 - 1입니다. 이 둘을 비트 단위로 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'; }

관련 정보