क्यों लूप तेजी से पुनरावृत्ति से हैं?


18

व्यवहार में मैं समझता हूं कि किसी भी पुनरावृत्ति को एक लूप (और इसके विपरीत?) के रूप में लिखा जा सकता है और अगर हम वास्तविक कंप्यूटरों से मापते हैं तो हम पाते हैं कि लूप उसी समस्या के लिए पुनरावृत्ति से तेज हैं। लेकिन क्या कोई सिद्धांत है जो इस अंतर को बनाता है या क्या यह मुख्य रूप से अनुकरणीय है?


9
लुक्स केवल उन भाषाओं में पुनरावृत्ति से अधिक तेज़ हैं जो उन्हें खराब तरीके से लागू करते हैं। उचित पूंछ पुनरावृत्ति के साथ एक भाषा में, पुनरावर्ती कार्यक्रमों को पर्दे के पीछे छोरों में अनुवाद किया जा सकता है, इस मामले में कोई अंतर नहीं होगा क्योंकि वे समान हैं।
शाम

3
हां, और यदि आप ऐसी भाषा का उपयोग करते हैं जो इसका समर्थन करती है, तो आप बिना किसी नकारात्मक प्रदर्शन प्रभाव के (पूंछ) पुनरावृत्ति का उपयोग कर सकते हैं।
jmite

1
@jmite, पूंछ पुनरावृत्ति जो वास्तव में एक लूप में अनुकूलित की जा सकती है, बहुत दुर्लभ है, जितना आप सोचते हैं उतना दुर्लभ है। विशेष रूप से उन भाषाओं में जो संदर्भ प्रकारों को प्रबंधित चर जैसे प्रबंधित करती हैं।
जोहान - मोनिका

1
चूंकि आपने टैग समय-जटिलता को शामिल किया है, मुझे लगता है कि मुझे यह जोड़ना चाहिए कि लूप के साथ एक एल्गोरिथ्म में पुनरावृत्ति के साथ एल्गोरिथ्म के रूप में एक ही समय की जटिलता है, लेकिन बाद के साथ, कुछ निरंतर कारक के आधार पर लिया गया समय अधिक होगा। पुनरावृत्ति के लिए उपरि की राशि।
लेउवे विन्खुइजेन

2
अरे, चूंकि आपने बहुत सारे अच्छे उत्तरों के साथ बहुत सारी संभावनाओं को समाप्त कर दिया है, तो क्या आपको कुछ और चाहिए या ऐसा महसूस होना चाहिए कि कुछ स्पष्ट किया जाना चाहिए? मेरे पास जोड़ने के लिए बहुत कुछ नहीं है, मैं कुछ उत्तर संपादित कर सकता हूं या टिप्पणी छोड़ सकता हूं, इसलिए यह सामान्य (व्यक्तिगत नहीं) प्रश्न है।
ईविल

जवाबों:


17

कारण यह है कि लूप पुनरावृत्ति की तुलना में तेज़ हैं आसान है।
विधानसभा में एक लूप इस तरह दिखता है।

mov loopcounter,i
dowork:/do work
dec loopcounter
jmp_if_not_zero dowork

लूप काउंटर के लिए एक एकल सशर्त कूद और कुछ बहीखाता।

पुनरावर्तन (जब यह संकलक द्वारा अनुकूलित नहीं किया जा सकता है या नहीं किया जा सकता है) इस तरह दिखता है:

start_subroutine:
pop parameter1
pop parameter2
dowork://dowork
test something
jmp_if_true done
push parameter1
push parameter2
call start_subroutine
done:ret

यह बहुत अधिक जटिल है और आपको कम से कम 3 कूदता है (यह देखने के लिए 1 परीक्षण कि क्या किया गया था, एक कॉल और एक वापसी)।
इसके अलावा पुनरावृत्ति में मापदंडों को स्थापित करने और लाने की आवश्यकता है।
इस सामान में से किसी भी एक लूप की आवश्यकता नहीं है, क्योंकि सभी पैरामीटर पहले से ही सेट किए गए हैं।

सैद्धांतिक रूप से पैरामीटर पुनरावृत्ति के साथ-साथ रह सकते हैं, लेकिन कोई भी संकलक जो मुझे नहीं पता है कि वास्तव में उनके अनुकूलन में दूर जाना है।

एक कॉल और एक जेएमपी के बीच अंतर
एक कॉल-रिटर्न जोड़ी बहुत अधिक महंगी नहीं है फिर जेएमपी। जोड़ी में 2 चक्र लगते हैं और जेएमपी 1 लेता है; शायद ही ध्यान देने योग्य।
कॉलिंग कन्वेंशनों में, जो मापदंडों को ओवरहेड में न्यूनतम रजिस्टर करने में सहायक होते हैं, लेकिन जब तक सीपीयू के बफ़र ओवरफ्लो नहीं होते, तब तक स्टैक पैरामीटर सस्ते होते हैं ।
यह कॉल कन्वेंशन और पैरामीटर हैंडलिंग द्वारा निर्धारित कॉल सेटअप का ओवरहेड है जो पुनरावृत्ति को धीमा करता है।
यह बहुत अधिक कार्यान्वयन पर निर्भर है।

खराब पुनरावृत्ति से निपटने का उदाहरण, उदाहरण के लिए, यदि एक पैरामीटर पारित किया जाता है जिसे संदर्भ गिना जाता है (उदाहरण के लिए एक गैर कास्ट प्रबंधित प्रकार पैरामीटर) तो यह संदर्भ गणना के बंद समायोजन को पूरा करने वाले 100 चक्रों को जोड़ देगा, पूरी तरह से प्रदर्शन बनाम एक लूप को मार देगा।
ऐसी भाषाओं में जिन्हें इस बुरे व्यवहार की पुनरावृत्ति के लिए तैयार किया जाता है, वे नहीं होती हैं।

CPU ऑप्टिमाइज़ेशन
अन्य कारण पुनरावृत्ति धीमा है, यह CPU के अनुकूलन तंत्रों के विरुद्ध काम करता है।
रिटर्न केवल सही ढंग से भविष्यवाणी की जा सकती है अगर उनमें से बहुत सारे एक पंक्ति में नहीं हैं। सीपीयू में कुछ (कुछ) मुट्ठी भर प्रविष्टियों के साथ एक रिटर्न स्टैक बफर है। एक बार हर अतिरिक्त रिटर्न देने वालों को भारी देरी का कारण बना दिया जाएगा।
किसी भी सीपीयू पर जो स्टैक रिटर्न बफर कॉल आधारित पुनरावर्तन का उपयोग करता है जो बफर आकार से अधिक है, सबसे अच्छा बचा जाता है।

पुनरावर्तन का उपयोग करके तुच्छ कोड उदाहरणों के बारे में
यदि आप फाइबोनैचि संख्या पीढ़ी की तरह पुनरावृत्ति का एक तुच्छ उदाहरण का उपयोग करते हैं, तो ये प्रभाव नहीं होते हैं, क्योंकि पुनरावर्तन के बारे में 'पता' करने वाला कोई भी कंपाइलर इसे लूप में बदल देगा, ठीक उसी तरह जैसे कोई प्रोग्रामर अपने नमक के लायक होता है। चाहेंगे।
यदि आप इन तुच्छ उदाहरणों को एक एनवायरमेंट में चलाते हैं जो कॉल स्टैक विल (अनावश्यक रूप से) सीमा से बाहर बढ़ने की तुलना में ठीक से अनुकूलन नहीं करता है।

पूंछ पुनरावृत्ति के बारे में
ध्यान दें कि कभी-कभी संकलक दूर की लकीर को लूप में बदलकर अनुकूलन करता है। यह केवल उन भाषाओं में इस व्यवहार पर भरोसा करने के लिए सबसे अच्छा है जिनके पास इस संबंध में एक अच्छा ट्रैक रिकॉर्ड है।
कई भाषाएं अंतिम पुनरावृत्ति को रोकने से पहले छिपे हुए साफ कोड को सम्मिलित करती हैं।

सच और छद्म पुनरावृत्ति के बीच भ्रम
यदि आपका प्रोग्रामिंग वातावरण आपके पुनरावर्ती स्रोत कोड को लूप में बदल देता है, तो यह निश्चित रूप से सही पुनरावृत्ति नहीं है जिसे निष्पादित किया जा रहा है।
ट्रू रिकर्सन को ब्रेडक्रंब के एक स्टोर की आवश्यकता होती है, ताकि पुनरावृत्ति की दिनचर्या उसके बाहर निकलने के बाद अपने कदमों का पता लगा सके।
यह इस निशान की हैंडलिंग है जो लूप का उपयोग करने की तुलना में पुनरावृत्ति को धीमा बनाता है। यह प्रभाव वर्तमान सीपीयू कार्यान्वयन द्वारा ऊपर उल्लिखित के रूप में बढ़ाया जाता है।

प्रोग्रामिंग वातावरण का प्रभाव
यदि आपकी भाषा पुनर्संरचना अनुकूलन की ओर अग्रसर है तो हर तरह से आगे बढ़ें और हर अवसर पर पुनरावृत्ति का उपयोग करें। ज्यादातर मामलों में भाषा आपकी पुनरावृत्ति को किसी प्रकार के लूप में बदल देगी।
उन मामलों में जहां यह नहीं हो सकता है, प्रोग्रामर को भी मुश्किल से दबाया जाएगा। यदि आपकी प्रोग्रामिंग भाषा पुनरावृत्ति की ओर नहीं है, तो इसे तब तक टाला जाना चाहिए जब तक डोमेन पुनरावृत्ति के लिए अनुकूल न हो।
दुर्भाग्य से कई भाषाएं पुनरावृत्ति को अच्छी तरह से संभाल नहीं पाती हैं।

पुनरावर्तन का दुरुपयोग पुनरावृत्ति
का उपयोग करके फाइबोनैचि अनुक्रम की गणना करने की कोई आवश्यकता नहीं है, वास्तव में यह एक पैथोलॉजिकल उदाहरण है।
पुनर्संयोजन का उपयोग उन भाषाओं में किया जाता है जो स्पष्ट रूप से इसका समर्थन करते हैं या उन डोमेन में जहां पुनरावृत्ति चमकती है, जैसे किसी पेड़ में संग्रहीत डेटा की हैंडलिंग।

मैं समझता हूं कि किसी भी पुनरावृत्ति को एक लूप के रूप में लिखा जा सकता है

हां, अगर आप घोड़े से पहले गाड़ी लगाने को तैयार हैं।
पुनरावृत्ति के सभी उदाहरणों को लूप के रूप में लिखा जा सकता है, उनमें से कुछ उदाहरणों में आपको भंडारण जैसे स्पष्ट स्टैक का उपयोग करने की आवश्यकता होती है।
यदि आपको अपने स्वयं के स्टैक को केवल लूप में पुनरावर्ती कोड को चालू करने की आवश्यकता है, तो आप सादे पुनरावर्तन का उपयोग कर सकते हैं।
जब तक कि आपको पेड़ की संरचना में प्रगणकों का उपयोग करने जैसी विशेष आवश्यकताएं नहीं मिली हैं और आपके पास उचित भाषा समर्थन नहीं है।


16

ये अन्य उत्तर कुछ भ्रामक हैं। मैं मानता हूं कि वे कार्यान्वयन विवरण देते हैं जो इस असमानता की व्याख्या कर सकते हैं, लेकिन वे मामले से आगे निकल जाते हैं। जैसा कि सही ढंग से जेमाइट द्वारा सुझाया गया है, वे कार्यान्वयन-उन्मुख हैं फ़ंक्शन कॉल / पुनरावृत्ति के टूटे हुए कार्यान्वयन की । कई भाषाएं लय के माध्यम से लूप को लागू करती हैं, इसलिए लूप स्पष्ट रूप से उन भाषाओं में तेजी से नहीं जा रहे हैं। पुनरावर्तन सिद्धांत में लूपिंग (जब दोनों लागू होते हैं) की तुलना में कम कुशल नहीं है। मुझे गाइ स्टील के 1977 के पेपर के सार को "एक्सपेंसिव प्रोसीजर कॉल" मिथक से अवगत कराते हुए, मिथक या, प्रोसीजर इम्प्लीमेन्ट्स माने जाने वाले हानिकारक या लैम्बडा: अल्टीमेट गोटो

लोककथाओं में कहा गया है कि गोटो बयान "सस्ते" हैं, जबकि प्रक्रिया कॉल "महंगी" हैं। यह मिथक काफी हद तक खराब तरीके से तैयार किए गए भाषा कार्यान्वयन का परिणाम है। इस मिथक का ऐतिहासिक विकास माना जाता है। सैद्धांतिक विचारों और मौजूदा कार्यान्वयन दोनों पर चर्चा की जाती है जो इस मिथक को खत्म करते हैं। यह दिखाया गया है कि प्रक्रिया कॉल का अप्रतिबंधित उपयोग महान शैलीगत स्वतंत्रता की अनुमति देता है। विशेष रूप से, किसी भी फ्लोचार्ट को "संरचित" प्रोग्राम के रूप में लिखा जा सकता है, बिना अतिरिक्त चर पेश किए। गोटो बयान और प्रक्रिया कॉल के साथ कठिनाई अमूर्त प्रोग्रामिंग अवधारणाओं और ठोस भाषा निर्माणों के बीच संघर्ष के रूप में विशेषता है।

"अमूर्त प्रोग्रामिंग अवधारणाओं और ठोस भाषा निर्माणों के बीच संघर्ष" को इस तथ्य से देखा जा सकता है कि सबसे सैद्धांतिक मॉडल, उदाहरण के लिए, अनकैप्ड लैम्ब्डा कैलकुलस , एक स्टैक नहीं है । बेशक, यह संघर्ष आवश्यक नहीं है, क्योंकि उपरोक्त कागज दिखाता है और जैसा कि उन भाषाओं द्वारा भी दिखाया गया है जिनके पास हस्केल जैसे पुनरावृत्ति के अलावा कोई पुनरावृत्ति तंत्र नहीं है।

fixfix f x = f (fix f) x(λएक्स)एन[एन/एक्स][एन/एक्स]एक्सएन

अब एक उदाहरण के लिए। के factरूप में परिभाषित करें

fact = fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) 1

यहाँ के मूल्यांकन है fact 3जहां, सघनता के लिए, मैं का उपयोग करेंगे, gके लिए पर्याय के रूप में fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)), यानी fact = g 1। यह मेरे तर्क को प्रभावित नहीं करता है।

fact 3 
~> g 1 3
~> fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) 1 3 
~> (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) g 1 3
~> (λa.λn.if n == 0 then a else g (a*n) (n-1)) 1 3
~> (λn.if n == 0 then 1 else g (1*n) (n-1)) 3
~> if 3 == 0 then 1 else g (1*3) (3-1)
~> g (1*3) (3-1)
~> g 3 2
~> fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) 3 2
~> (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) g 3 2
~> (λa.λn.if n == 0 then a else g (a*n) (n-1)) 3 2
~> (λn.if n == 0 then 3 else g (3*n) (n-1)) 2
~> if 2 == 0 then 3 else g (3*2) (2-1)
~> g (3*2) (2-1)
~> g 6 1
~> fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) 6 1
~> (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) g 6 1
~> (λa.λn.if n == 0 then a else g (a*n) (n-1)) 6 1
~> (λn.if n == 0 then 6 else g (6*n) (n-1)) 1
~> if 1 == 0 then 6 else g (6*1) (1-1)
~> g (6*1) (1-1)
~> g 6 0
~> fix (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) 6 0
~> (λf.λa.λn.if n == 0 then a else f (a*n) (n-1)) g 6 0
~> (λa.λn.if n == 0 then a else g (a*n) (n-1)) 6 0
~> (λn.if n == 0 then 6 else g (6*n) (n-1)) 0
~> if 0 == 0 then 6 else g (6*0) (0-1)
~> 6

आप बिना विवरण देखे भी आकृति से देख सकते हैं कि कोई वृद्धि नहीं है और प्रत्येक पुनरावृत्ति को उतनी ही जगह की आवश्यकता है। (तकनीकी रूप से, संख्यात्मक परिणाम बढ़ता है जो अपरिहार्य है और एक whileलूप के लिए सही है ।) मैं आपको यहां "बढ़ती" स्टैक को इंगित करने के लिए अवहेलना करता हूं।

ऐसा लगता है कि लैम्ब्डा कैलकुलस के पहले शब्द का अर्थ है "पूंछ कॉल ऑप्टिमाइज़ेशन" जो आमतौर पर गलत है। बेशक, यहां कोई "अनुकूलन" नहीं हो रहा है। "सामान्य" कॉल के विपरीत "पूंछ" कॉल के लिए यहां कोई विशेष नियम नहीं हैं। इस कारण से, "कॉल" ऑप्टिमाइज़ेशन क्या "कॉलिंग" ऑप्टिमाइज़ेशन का "अमूर्त" लक्षण वर्णन करना कठिन है, क्योंकि फंक्शन कॉल सिमेंटिक्स के कई अमूर्त लक्षण वर्णन में, टेल कॉल "ऑप्टिमाइज़ेशन" करने के लिए कुछ भी नहीं है!

की अनुरूप परिभाषा fact कई भाषाओं में "स्टैक ओवरफ्लो" की एक , उन भाषाओं द्वारा फंक्शन कॉल सेमेंटिक्स को सही ढंग से लागू करने में विफलता है। (कुछ भाषाओं में एक बहाना है।) भाषा कार्यान्वयन के लिए स्थिति मोटे तौर पर एक समान है जो लिंक वाली सूचियों के साथ सरणियों को लागू करती है। ऐसे "सरणियों" में अनुक्रमण तब एक O (n) ऑपरेशन होगा जो सरणियों की अपेक्षा को पूरा नहीं करता है। यदि मैंने भाषा का एक अलग कार्यान्वयन किया, जो कि लिंक की गई सूचियों के बजाय वास्तविक सरणियों का उपयोग करता है, तो आप कहेंगे कि मैंने "सरणी एक्सेस ऑप्टिमाइज़ेशन" लागू नहीं किया है, तो आप कहेंगे कि मैंने सरणियों के टूटे कार्यान्वयन को ठीक किया।

तो, Veedrac के जवाब का जवाब। ढेर पुनरावृत्ति के लिए "मौलिक" नहीं हैं । इस हद तक कि "स्टैक-लाइक" व्यवहार मूल्यांकन के दौरान होता है, यह केवल उन मामलों में हो सकता है जहां लूप (एक सहायक डेटा संरचना के बिना) पहले स्थान पर लागू नहीं होगा! इसे दूसरे तरीके से रखने के लिए, मैं लूप्स को पुनरावृत्ति के साथ लागू कर सकता हूं, बिल्कुल उसी प्रदर्शन विशेषताओं के साथ। दरअसल, स्कीम और एसएमएल दोनों में लूपिंग कंस्ट्रक्शन होते हैं, लेकिन दोनों ही उन लोगों को रिकर्सन के संदर्भ में परिभाषित करते हैं (और, कम से कम स्कीम में, doअक्सर को लागू किया एक मैक्रो के रूप में जाता है जो पुनरावर्ती कॉल में फैलता है।) इसी तरह, जोहान के जवाब के लिए, कुछ भी नहीं कहता है। संकलक को पुनरावृत्ति के लिए वर्णित असेंबली जोहान का उत्सर्जन करना चाहिए। वास्तव में, जाता है, बाध्य है असेंबली आप लूप्स या रिकर्सन का उपयोग करते हैं। केवल एक बार संकलक (कुछ) होगाजोहान का वर्णन करने के लिए विधानसभा के समान ही है जब आप कुछ ऐसा कर रहे हैं जो वैसे भी लूप द्वारा व्यक्त नहीं होता है। जैसा कि स्टील के पेपर में उल्लिखित है और हास्केल, स्कीम और एसएमएल जैसी भाषाओं के वास्तविक अभ्यास द्वारा प्रदर्शित किया गया है, यह "अत्यधिक दुर्लभ" नहीं है कि पूंछ कॉल को "अनुकूलित" किया जा सकता है, वे हमेशा कर सकते हैं "अनुकूलित" किया जा सकता है। क्या पुनरावृत्ति का एक विशेष उपयोग निरंतर स्थान पर चलेगा यह इस बात पर निर्भर करता है कि यह कैसे लिखा जाता है, लेकिन आपको जो संभव हो उसे लागू करने के लिए प्रतिबंधों की आवश्यकता होती है वे प्रतिबंध हैं जिन्हें आपको अपनी समस्या को लूप के आकार में फिट करने की आवश्यकता होगी। (वास्तव में, वे कम कड़े हैं। समस्याएं हैं, जैसे कि एन्कोडिंग स्टेट मशीन, जो कि अधिक स्पष्ट रूप से और कुशलता से टेल कॉल के माध्यम से नियंत्रित की जाती हैं, लूप के विपरीत, जिसके लिए सहायक चर की आवश्यकता होगी।) फिर से। लिए अधिक काम करने की आवश्यकता होती है। जब भी आपके कोड में एक लूप नहीं होता है।

मेरा अनुमान है कि जोहान सी संकलकों का जिक्र कर रहा है जिनके मनमाने ढंग से प्रतिबंध हैं जब वह पूंछ कॉल "अनुकूलन" करेगा। जोहान को संभवतः C ++ और Rust जैसी भाषाओं का उल्लेख है जब वह "प्रबंधित प्रकारों के साथ भाषाओं" के बारे में बात करता है। आरए II सी ++ से मुहावरा और जंग में मौजूद रूप में अच्छी तरह चीजें हैं जो ऊपरी तौर पर पूंछ कॉल, नहीं पूंछ कॉल की तरह लग रहे (क्योंकि "विनाशकर्ता" अभी भी जरूरत के नाम से जाना) बनाता है। कुछ अलग सिंटैक्स का उपयोग करने के लिए कुछ अलग सिमेंटिक्स का उपयोग करने के प्रस्ताव दिए गए हैं, जो पूंछ की पुनरावृत्ति (अर्थात् पहले विध्वंसक कॉल करने की अनुमति देगा)अंतिम पूंछ कॉल और स्पष्ट रूप से "नष्ट" वस्तुओं तक पहुंच को अस्वीकार करना)। (कचरा संग्रहण में ऐसा कोई मुद्दा नहीं है, और हास्केल, एसएमएल और योजना के सभी कचरा एकत्र की गई भाषाएं हैं।) एक बहुत अलग नस में, कुछ भाषाएं, जैसे कि स्मॉलटाकल, "स्टैक" को प्रथम श्रेणी की वस्तु के रूप में उजागर करती हैं, इनमें "स्टैक" अब एक कार्यान्वयन विवरण नहीं है, हालांकि यह अलग-अलग शब्दार्थों के साथ अलग-अलग प्रकार के कॉल को रोकता नहीं है। (जावा का कहना है कि यह सुरक्षा के कुछ पहलुओं को संभालने के तरीके के कारण नहीं हो सकता है, लेकिन यह वास्तव में गलत है ।)

व्यवहार में, फ़ंक्शन कॉल के टूटे हुए कार्यान्वयन का प्रसार तीन मुख्य कारकों से होता है। सबसे पहले, कई भाषाएं अपनी कार्यान्वयन भाषा (आमतौर पर सी) से टूटे हुए कार्यान्वयन को विरासत में लेती हैं। दूसरा, निर्धारक संसाधन प्रबंधन अच्छा है और इस मुद्दे को और अधिक जटिल बना देता है, हालांकि केवल कुछ मुट्ठी भर भाषाएं ही इसे पेश करती हैं। तीसरा, और, मेरे अनुभव में, ज्यादातर लोग इस बात की परवाह करते हैं, कि वे डीबगिंग उद्देश्यों के लिए त्रुटि होने पर स्टैक के निशान चाहते हैं। केवल दूसरा कारण एक है जो संभावित रूप से सैद्धांतिक रूप से प्रेरित हो सकता है।


मैंने "मूलभूत" का उपयोग सबसे बुनियादी कारण को संदर्भित करने के लिए किया था कि यह दावा सही है, न कि यह तार्किक रूप से इस तरह से होना चाहिए (जो स्पष्ट रूप से ऐसा नहीं करता है, क्योंकि दोनों कार्यक्रम समान रूप से समान हैं)। लेकिन मैं आपकी टिप्पणी से पूरी तरह असहमत हूं। लैम्ब्डा कैलकुलस का आपका उपयोग स्टैक को उतना नहीं हटाता जितना इसे अस्पष्ट करता है।
विड्रैक

आपका दावा "केवल एक बार संकलक (कुछ) असेंबली का उत्सर्जन करने के लिए बाध्य होगा जैसे जोहान का वर्णन है जब आप कुछ ऐसा कर रहे हैं जो वैसे भी लूप द्वारा व्यक्त नहीं होता है।" यह भी काफी अजीब है; एक कंपाइलर (सामान्य रूप से) किसी भी कोड का उत्पादन करने में सक्षम होता है जो एक ही आउटपुट का उत्पादन करता है, इसलिए आपकी टिप्पणी मूल रूप से एक टैटोलॉजी है। लेकिन व्यवहार में संकलक अलग-अलग समकक्ष कार्यक्रमों के लिए अलग-अलग कोड का उत्पादन करते हैं, और सवाल यह था कि क्यों।
विड्रैक

हे(1)

एक सादृश्य देने के लिए, एक सवाल का जवाब देते हुए कि लूप में अपरिवर्तनीय तारों को जोड़ने से "यह होने की आवश्यकता नहीं है" के साथ द्विघात समय लगता है, लेकिन पूरी तरह से उचित होगा, लेकिन यह दावा करने पर कि कार्यान्वयन इस प्रकार टूट गया नहीं होगा।
विड्रैक

बहुत दिलचस्प जवाब। भले ही यह एक शेख़ी :-) जैसा लगता है। अपवित्र क्योंकि मैंने कुछ नया सीखा है।
जोहान -

2

मौलिक रूप से अंतर यह है कि पुनरावृत्ति में एक स्टैक शामिल है, एक सहायक डेटा संरचना जिसे आप शायद नहीं चाहते हैं, जबकि लूप स्वचालित रूप से ऐसा नहीं करते हैं। केवल दुर्लभ मामलों में एक विशिष्ट कंपाइलर है जो यह सुनिश्चित करने में सक्षम है कि आपको वास्तव में स्टैक की आवश्यकता नहीं है।

यदि आप इसके बजाय तुलना किए गए स्टैक पर मैन्युअल रूप से काम कर रहे लूप्स की तुलना करते हैं (उदाहरण के लिए, मेमोरी को ढेर करने के लिए एक पॉइंटर के माध्यम से), तो आप आमतौर पर उन्हें हार्डवेयर स्टैक का उपयोग करने की तुलना में अधिक तेज़ या धीमा नहीं पाएंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.