का उपयोग क्यों कर रहा है और & lt; & nbsp; की तुलना में faster५ गुना अधिक तेज है


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...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"

क्या बिना सुस्ती के ब्लॉक की स्पष्टता होनी चाहिए थी?

अपडेट (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: एक नंबर n का कोई कारक n / 2 से अधिक नहीं है, इसलिए आपको अभी भी सभी मिलेंगे ऐसा करने से गैर-अभाज्य संख्याओं के लिए कारक। (यदि आप केवल प्रधानता के लिए परीक्षण में रुचि रखते थे , तो यह sqrt (n) तक पुनरावृत्त करने के लिए पर्याप्त होगा, लेकिन बैश में वैसे भी वर्गमूल की गणना करने के लिए एक अंतर्निहित फ़ंक्शन नहीं है।)
माल्टे स्कॉरुप्पा

मैट, अच्छी बात (+1)। एकमात्र परिवर्तन यह था कि संख्या 4 के लिए काम नहीं किया था इसलिए मुझे इसके (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" है - जब [एक तर्क दिया जाता है, तो परिणाम सफल होता है यदि तर्क गैर-रिक्त है, और यह शाब्दिक स्ट्रिंग हमेशा गैर-रिक्त है, इसलिए हमेशा "सही" है।

पठनीयता के लिए, मैं बहुत लंबी लाइन बदलूंगा

[ $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
यह भी ध्यान देने योग्य है कि बाश, zsh, एट अल, [में एक प्रोग्राम का शाब्दिक रूप से आह्वान किया जाता है [, जबकि [[इसे शेल में लागू किया जाता है - इसलिए यह तेज़ होगा। कोशिश करो time for ((i = 0; $i < 1000; i++)); do [ 1 ]; doneऔर तुलना करें [[। अधिक जानकारी के लिए इस SO प्रश्न को देखें ।
किर्ब

2
बैश लागू करता है [, यह एक बिलिन है। शेल प्रॉम्प्ट से, टाइप करें type -a [औरhelp [
ग्लेन जैकमैन 14

@glennjackman वाह; उस के बारे में पता नहीं था। मैंने मान लिया कि यह अभी भी मामला है क्योंकि 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लूप आपके नेस्टेड लूप्स को काफी अच्छी तरह से डुप्लिकेट करता है:

यह उतना नहीं छपता, बेशक, मैंने वह सब नहीं लिखा था, लेकिन, उदाहरण के लिए, छत को १०१ के बजाय १०१ के रूप में सेट करना लिखा है और ...

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" ] ) && ...

... और जिस तरह से मैंने इसे 101 के सीलिंग के लिए कई गोले में ऊपर लिखा dashथा और इसे .017 सेकंड में उप-संस्करण के बिना और 1.8 सेकंड में उप-संस्करण के साथ किया। busybox.149 और 2, zsh .149 और 4, bash.35 और 6, और ksh93.149 और .160 में। ksh93अन्य गोले के रूप में उपधारा के लिए कांटा नहीं है। तो शायद समस्या इतनी अधिक नहीं है क्योंकि यह खोल है


[ "$((...))" -eq "$((...))" ]ओवर का क्या फायदा (( (...) == (...) ))? क्या बाद वाला कम पोर्टेबल है?
रुख

@ruakh - पोर्टेबिलिटी, गति, विश्वसनीयता। [ "$((...))" -eq "$((...)) ]ऐसे गोले में काम करता है जो प्रोग्राम को चलाने के लिए 15 सेकंड नहीं लेते हैं, और दूसरा नहीं करता है। यदि एक दूसरे पर एक का लाभ बिल्कुल संदिग्ध है, तो वह केवल पूर्व को बढ़त दे सकता है, जिसका अर्थ है कि उपयोग करने के लिए एक अच्छा कारण नहीं है (( (...) == (...) ))
mikeserv

क्षमा करें, लेकिन आपका उत्तर यह मानता है कि मुझे पहले से ही शेल समर्थन का विस्तृत ज्ञान है (( ... ))। मैं खुश हूँ, लेकिन मैं है कि विस्तृत जानकारी नहीं। (याद रखें, मैं वही हूँ जो सिर्फ पूछा जाता है कि (( ... ))क्या कम पोर्टेबल है।) तो मैं वास्तव में आपके उत्तर की समझ में नहीं आ सकता। : - / क्या आप कुछ अधिक स्पष्ट हो सकते हैं?
रक्ख

@ruakh - मुझे क्षमा करें ... मैंने नहीं देखा कि आप पूछ रहे थे कि क्या यह अधिक पोर्टेबल था, बस यह कैसे फायदेमंद था - यही कारण है कि मैंने पोर्टेबिलिटी के बारे में जवाब दिया। वैसे भी, "$((...))"है POSIX द्वारा निर्दिष्ट और अन्य एक खोल विस्तार है। POSIX गोले बहुत सक्षम हैं। यहां तक कि dashऔर poshसही ढंग से की तरह शाखा परीक्षण संभाल लेंगे "$((if_true ? (var=10) : (var=5) ))"और हमेशा आवंटित $varसही ढंग से। busyboxवहाँ टूटता है - यह हमेशा दोनों पक्षों के $if_trueमूल्य की परवाह किए बिना विकसित होता है ।
मिकसेर

@ruakh - अरे यार। मुझे आज थोड़ा दूर होना चाहिए ... यह वहीं कहता है ... क्या बाद वाला कम पोर्टेबल है ? मुझे नहीं लगा कि पहले, मुझे लगता है ...?
mikeserv
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.