&&を使用することが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組み込みまたはコマンドが呼び出されます。 1つの引数、文字列 "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他のシェルのようにサブシェルを分岐する必要はありません。したがって、問題はサブシェルにあるのではありませんシェル

関連情報