&&를 사용하는 것이 if...fi보다 75배 빠른 이유와 코드를 더 깔끔하게 만드는 방법

&&를 사용하는 것이 if...fi보다 75배 빠른 이유와 코드를 더 깔끔하게 만드는 방법

다음 작업 코드가 있습니다.

largest_prime=1
for number_under_test in {1..100}
do
  is_prime=true
  factors=''
  for ((divider = 2; divider < number_under_test-1; divider++));
  do
    remainder=$(($number_under_test % $divider))
    [ $remainder == 0 ] && [ is_prime ] && is_prime=false && factors+=$divider' '
  done
  [ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)"  [ $is_prime == true ] && largest_prime=$number_under_test
done
printf "\nLargest Prime= $largest_prime\n"

이 코드는 0.194초의 빠른 속도로 실행됩니다. 하지만 && is_prime= false읽기가 약간 어려웠고 (훈련받지 않은 눈에는) 설정되기보다는 테스트 중인 것처럼 보입니다. 그래서 &&an 으로 변경해 보았는데 if...then효과가 있었습니다. 하지만 14.48초로 75배 느렸습니다. 숫자가 높을수록 가장 눈에 띕니다.

largest_prime=1
for number_under_test in {1..100}
do
  is_prime=true
  factors=''
  for ((divider = 2; divider < number_under_test-1; divider++));
  do  
    remainder=$(($number_under_test % $divider))
    if ([ $remainder == 0 ] && [ $is_prime == true ]); then
      is_prime=false
      factors+=$divider' '
    fi  
  done
  [ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)"  [ $is_prime == true ] && largest_prime=$number_under_test
done  
printf "\nLargest Prime= $largest_prime\n"

둔해 보이지 않고 블록을 날카롭게 유지하는 방법이 있습니까?

업데이트됨 (2015년 1월 4일 오전 10시 40분 ET)

좋은 피드백! 현재 다음을 사용하고 있습니다. 다른 제안은 없나요?

largest_prime=1
separator=' '
for number_under_test in {1..100}; {
  is_prime=true
  factors=''
  for ((divider = 2; divider < (number_under_test/2)+1; divider++)) {
    remainder=$(($number_under_test % $divider))
    if [ $remainder == 0 ]; then
      is_prime=false
      factors+=$divider' '
    fi
  } 
  if $is_prime; then
    printf "\n${number_under_test} IS prime\n\n"
    largest_prime=$number_under_test
  else
    printf "${number_under_test} is NOT prime, factors are: "
    printf "$factors\n"
  fi
}
printf "\nLargest Prime= $largest_prime\n"

답변1

그 이유는 매번 서브쉘을 생성하기 때문입니다.

if ([ $remainder == 0 ] && [ $is_prime == true ]); then

괄호만 제거하면 됩니다

if [ $remainder == 0 ] && [ $is_prime == true ]; then

명령을 그룹화하려면 다음 구문을 사용하면 됩니다.현재의껍데기:

if { [ $remainder == 0 ] && [ $is_prime == true ]; }; then

(후행 세미콜론이 필요합니다.수동)

이는 [ is_prime ]다음과 다릅니다 . 대괄호 없이 [ $is_prime == true ]간단히 작성하면 bash 내장 또는 명령이 호출됩니다. 하나의 인수, 문자열 "is_prime"을 취하는 테스트입니다. 인수가 주어졌을 때 인수가 비어 있지 않으면 결과는 성공이고 리터럴 문자열은 항상 비어 있지 않으므로 항상 "true"입니다.$is_primetruefalse
[ is_prime ][

가독성을 위해 매우 긴 줄을 바꾸겠습니다.

[ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)"  [ $is_prime == true ] && largest_prime=$number_under_test

도착하다

if [ $is_prime == true ]; then
  echo "${number_under_test} is prime!"
else 
  echo "${number_under_test} is NOT prime (factors= $factors)"
  # removed extraneous [ $is_prime == true ] test that you probably
  # didn't notice off the edge of the screen
  largest_prime=$number_under_test
fi

명확성을 높이기 위해 공백을 과소평가하지 마십시오.

답변2

내 생각엔 당신이 당신의 역할을 너무 열심히 하고 있는 것 같아요. 고려하다:

unset num div lprime; set -- "$((lprime=(num=(div=1))))"
while [     "$((     num += ! ( div *= ( div <= num   ) ) ))" -eq \
            "$((     num *=   ( div += 1 )   <= 101   ))" ]    && {
      set   "$(( ! ( num %      div )         * div   ))"     "$@"
      shift "$(( !    $1 +    ( $1 ==  1 )    *  $#   ))"
}; do [ "$div" -gt "$num" ] && echo "$*"      
done

쉘 연산은 자체적으로 정수 조건을 평가하는 능력이 매우 뛰어납니다. 너무 많은 테스트 및/또는 외부 과제가 필요한 경우는 거의 없습니다. 이 while루프는 중첩 루프를 훌륭하게 복제합니다.

그렇게 많이 인쇄되지는 않을 것이고, 물론 그렇게 많이 쓰지는 않았지만, 예를 들어 위에 적힌 대로 101이 아닌 16으로 상한선을 설정하고...

2
3
4 2
5
6 3 2
7
8 4 2
9 3
10 5 2
11
12 6 4 3 2
13
14 7 2
15 5 3

확실히 그 일을하고 있습니다. 출력을 대략적으로 계산하는 데는 거의 필요하지 않습니다.

...
do [ "$div" -eq "$num" ] && shift &&
   printf "$num ${1+!}= prime.${1+\t%s\t%s}\n" \
          "factors= $*"                        \
          "lprime=$(( lprime = $# ? lprime : num ))"
done

그냥 대신 해보세요 echo...

1 = prime.
2 = prime.
3 = prime.
4 != prime.     factors= 2      lprime=3
5 = prime.
6 != prime.     factors= 3 2    lprime=5
7 = prime.
8 != prime.     factors= 4 2    lprime=7
9 != prime.     factors= 3      lprime=7
10 != prime.    factors= 5 2    lprime=7
11 = prime.
12 != prime.    factors= 6 4 3 2        lprime=11
13 = prime.
14 != prime.    factors= 7 2    lprime=13
15 != prime.    factors= 5 3    lprime=13

이것은 busybox매우 이식성이 뛰어나고 빠르고 사용하기 쉽습니다.

서브쉘 문제는 대부분의 쉘에서 발생하지만 다음을 통해 수행됩니다.멀리, 껍질 중에서 가장 날카로운 것입니다 bash. 번갈아가며 해요

( [ "$div" -gt "$num" ] ) && ...

...위에서 한도가 dash101인 여러 쉘에 작성했는데 서브쉘이 없으면 0.017초, 서브쉘이 있으면 1.8초 만에 완료되었습니다. busybox.149 및 2, zsh .149 및 4, bash.35 및 6, ksh93.149 및 .160. ksh93다른 쉘처럼 서브쉘을 분기할 필요가 없습니다. 따라서 문제는 서브쉘에 있는 것이 아니라껍데기.

관련 정보