কেন && ব্যবহার করছে 75 বারের চেয়ে দ্রুত… ফাই এবং কীভাবে কোড পরিষ্কার করবেন


38

আমার নীচের ওয়ার্কিং কোড রয়েছে:

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পড়তে কিছুটা কঠিন পেয়েছি এবং এটি (প্রশিক্ষণহীন চোখের দিকে) দেখতে পেল যাতে এটি পরীক্ষিত হওয়ার পরিবর্তে এটি পরীক্ষা করা হচ্ছে যা এটি কি করে। তাই আমি পরিবর্তিত চেষ্টা &&একটি মধ্যে if...then14,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"

অলসতা ছাড়া ব্লকের স্পষ্টতা আছে কি?

আপডেট (1/4/2015 10:40 am EST)

দুর্দান্ত প্রতিক্রিয়া! আমি এখন নিম্নলিখিত ব্যবহার করছি। অন্য কোন প্রতিক্রিয়া ?

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
একপাশে, আপনার স্ক্রিপ্টটি চালানো Largest Prime= 100আমার কম্পিউটারে প্রিন্ট করে।
জিউলিও মাসকারেলো

3
পাশাপাশি, যদি আপনি দক্ষতায় আগ্রহী হন, তবে এটির উন্নতি করার জন্য একটি তুচ্ছ উপায় কেবলমাত্র পুনরাবৃত্তি করা number_under_test/2পরিবর্তে কেবল পুনরায় করা হবে number_under_test-1: একটি সংখ্যার এন এর কোনও ফ্যাক্টর এন / 2 এর চেয়ে বেশি নয়, সুতরাং আপনি এখনও সমস্ত কিছু খুঁজে পাবেন এটি করে অ-মৌলিক সংখ্যার জন্য কারণগুলি। (এছাড়াও আপনি যদি কেবল আধ্যাত্মিকতার জন্য পরীক্ষা করতে আগ্রহী হন তবে এটি স্কয়ারটি (এন) পর্যন্ত পুনরাবৃত্তি করা যথেষ্ট হবে, তবে বাশের যে কোনও উপায়ে
বর্গমূলের

ম্যাট, ভাল পয়েন্ট (+1)। একমাত্র পরিবর্তনটি ছিল যে (number_under_test/2)+1
মাইকেল ডুরান্ট

1
আপনার আপডেট সংস্করণে, ধনুর্বন্ধনী {}সত্যিই পর প্রয়োজন হয় না thenদফা কারণ thenইতিমধ্যে (সহ একটি গোষ্ঠীবদ্ধ অপারেটর হিসেবে কাজ করে elif, elseঅথবা fi)। আসলে, কয়েকটি শেলের মধ্যে আপনি লিখতে পারেন, উদাহরণস্বরূপ, for i in 1 2 3; { echo $i; }না doবা না দিয়ে done
জোনাথন লেফলার

1
+1 জোনাথন, আমি এই পরিবর্তনগুলি করেছি এবং আপডেটটি আপডেট করেছি
মাইকেল ডুরান্ট

উত্তর:


66

কারণ আপনি প্রতিবার একটি সাব-শেল তৈরি করছেন:

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 ]: আপনি এটি লিখতে পারতেন কেবল $is_prime(কোনও বন্ধনী ছাড়াই) যা অন্তর্নির্মিত trueবা falseকমান্ডটিকে অনুরোধ করবে।
[ is_prime ]একটি আর্গুমেন্টের সাথে একটি পরীক্ষা, স্ট্রিং "is_prime" - যখন [একটি একক যুক্তি দেওয়া হয়, তখন যুক্তিটি খালি না হলে ফলাফলটি সাফল্য হয় এবং সেই আক্ষরিক স্ট্রিংটি সর্বদা খালি থাকে না, তাই সর্বদা "সত্য" হয়।

পাঠযোগ্যতার জন্য, আমি খুব দীর্ঘ লাইনটি পরিবর্তন করব change

[ $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

স্বচ্ছতা বাড়ানোর জন্য সাদা স্পেসকে অবমূল্যায়ন করবেন না।


1
একটি টাইপো রয়েছে - largest_prime=$number_under_testতত্কালীন শাখায় হওয়া উচিত (একই ত্রুটিটি মূল ক্ষেত্রে)
জয়াওও

1
এটি আরও লক্ষণীয় যে বাশ, জেডএস, এট আল-এ [শাব্দিকভাবে বলা একটি প্রোগ্রাম শুরু করা হচ্ছে [, যেখানে [[শেলটি প্রয়োগ করা হয়েছে - সুতরাং এটি আরও দ্রুত হবে। চেষ্টা করুন time for ((i = 0; $i < 1000; i++)); do [ 1 ]; doneএবং তুলনা করুন [[। আরও তথ্যের জন্য এই তাই প্রশ্ন দেখুন ।
কিরব

2
বাশ সরঞ্জাম [, এটি একটি অন্তর্নির্মিত। শেল প্রম্পট থেকে, টাইপ করুন type -a [এবংhelp [
গ্লেন জ্যাকম্যান

নিবন্ধন করুন এটা সম্পর্কে অবগত ছিল না। আমি ধরে নিয়েছিলাম এটি এখনও ছিল কারণ which [এখনও ফিরে আসে /usr/bin/[। আমি ঠিক বুঝতে পেরেছিলাম যে আমি জেএসএস একইরকম বোঝাই; আমার জন্য এটি আমাকে বিল্টিন বলে। তবে তারপরে ... কেন [[দ্রুত?
কিরব

2
@glennjackman command -vআরেকটি ভাল whichবিকল্প; আরো দেখুন এখানে
আব্বাফাই

9

আমি মনে করি আপনি নিজের কাজটি খুব শক্তভাবে কাজ করছেন। বিবেচনা:

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। এটি অত্যন্ত বহনযোগ্য, দ্রুত এবং সহজেই ব্যবহারযোগ্য।

তোমার subshell ইস্যু সবচেয়ে শাঁস ঘটতে যাচ্ছে, কিন্তু এটা দ্বারা হয় পর্যন্ত , একটি সবচেয়ে তীব্র bashশেল। আমি করণীয় মধ্যে বিকল্প

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

... এবং যেভাবে আমি এটিকে উপরে 101 টি সিলিংয়ের জন্য কয়েকটি শেলের উপরে লিখেছিলাম এবং dashএটি .017 সেকেন্ডে সাবস্কেল ছাড়াই এবং 1.8 সেকেন্ডের মধ্যে সাব-শেল দিয়ে করেছি। busybox.149 এবং 2, zsh .149 এবং 4, bash.35 এবং 6, এবং ksh93.149 এবং .160 এ। ksh93অন্যান্য শেলগুলি যেমন দরকার তেমনি সাব-শেলের জন্য কাঁটাচামচ করে না। সুতরাং শেল হিসাবে সমস্যাটি এতটা সাবশেল নয় ।


[ "$((...))" -eq "$((...))" ]ওভার সুবিধা কি (( (...) == (...) ))? পরেরটি কি কম বহনযোগ্য?
রুওখ

@রুখ - বহনযোগ্যতা, গতি, নির্ভরযোগ্যতা। প্রোগ্রামটি চালাতে 15 সেকেন্ড সময় নেয় না এমন [ "$((...))" -eq "$((...)) ]শেলগুলিতে কাজ করে এবং অন্যটি হয় না। তাহলে অন্য ওভার এক সুবিধা সব সময়ে সন্দেহজনক হয়, তাহলে যে শুধুমাত্র সাবেক প্রান্ত, যার মানে নেই দিতে পারেন না ব্যবহার একটি ভাল কারণ । (( (...) == (...) ))
মাইক্রজারভের

দুঃখিত, তবে আপনার উত্তরটি ধরেই মনে হচ্ছে যে এর জন্য শেল সাপোর্ট সম্পর্কে আমার কাছে ইতিমধ্যে বিশদ জ্ঞান রয়েছে (( ... ))। আমি অভিভূত, কিন্তু আমি না যে বিস্তারিত জ্ঞান আছে না। (মনে রাখবেন, আমিই সেই ব্যক্তি যিনি জিজ্ঞাসা করেছিলেন যে (( ... ))কম পোর্টেবল কি না)) সুতরাং আমি আপনার জবাবটি সত্যই বুঝতে পারি না। : - / আপনি কি আরও কিছুটা স্পষ্ট হতে পারবেন?
রুরখ

@রুখ - আমি দুঃখিত ... আমি দেখতে পেলাম না যে আপনি এটি জিজ্ঞাসা করছেন যে এটি আরও পোর্টেবল, ঠিক কীভাবে এটি সুবিধাজনক - এই কারণেই আমি বহনযোগ্যতার বিষয়ে জবাব দিয়েছি। যাই হোক, "$((...))"হয় POSIX-নির্দিষ্ট এবং অন্য একটি শেল এক্সটেনশান। পসিক্স শেলগুলি বেশ সক্ষম। এমনকি dashএবং poshযথাযথভাবে শাখা পরীক্ষাগুলি পরিচালনা করে "$((if_true ? (var=10) : (var=5) ))"এবং সর্বদা $varসঠিকভাবে নির্ধারণ করে । busyboxসেখানে বিরতি দেয় - এটি সর্বদা উভয় পক্ষের $if_trueমান নির্বিশেষে পরিষ্কার করে ।
মাইক্রজারভের

@রুখ - ওহ মানুষ আমার আজ অবশ্যই কিছুটা দূরে থাকা উচিত ... এটা ঠিক আছে এখানে ... পরেরটি কি কম বহনযোগ্য ? আমি এর আগে দেখিনি, আমার ধারণা ...?
মাইক্রজারভের
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.