एक फ़ंक्शन है जो Math.random () शुद्ध कहता है?


112

निम्नलिखित एक शुद्ध कार्य है?

function test(min,max) {
   return  Math.random() * (max - min) + min;
}

मेरी समझ यह है कि एक शुद्ध कार्य इन स्थितियों का अनुसरण करता है:

  1. यह मापदंडों से गणना मूल्य लौटाता है
  2. यह रिटर्न वैल्यू की गणना के अलावा कोई काम नहीं करता है

यदि यह परिभाषा सही है, तो क्या मेरा कार्य शुद्ध कार्य है? या शुद्ध कार्य को गलत समझने की मेरी समझ क्या है?


66
"यह रिटर्न वैल्यू की गणना के अलावा कोई काम नहीं करता है" लेकिन यह कॉल करता है Math.random()जो आरएनजी की स्थिति को बदलता है।
पॉल ड्रेपर

1
दूसरा बिंदु अधिक है जैसे "यह बाहरी (फ़ंक्शन में) स्थिति को नहीं बदलता है"; और पहले को कुछ हद तक पूरक होना चाहिए "यह SAME मापदंडों से गणना की गई SAME मान लौटाता है", क्योंकि लोगों ने नीचे लिखा है
MVCDS

क्या यादृच्छिकता के लिए अनुमति देते हुए एक अर्धवृत्त समारोह की धारणा है? उदा। test(a,b)हमेशा एक ही वस्तु Random(a,b)(जो विभिन्न ठोस संख्याओं का प्रतिनिधित्व कर सकता है) लौटाता है ? यदि आप Randomप्रतीकात्मक रखते हैं तो यह शास्त्रीय अर्थों में शुद्ध है, यदि आप इसका प्रारंभिक मूल्यांकन करते हैं और संख्याओं में डालते हैं, तो शायद एक प्रकार के अनुकूलन के रूप में, फ़ंक्शन अभी भी कुछ "शुद्धता" को बरकरार रखता है।
जेडएम

1
"कोई भी जो यादृच्छिक अंकों के उत्पादन के अंकगणितीय तरीकों पर विचार करता है, निश्चित रूप से, पाप की स्थिति में है।" - जॉन वॉन न्यूमैन
स्टीव कूओ 20

1
@ जेडडीएम यदि आप "अर्ध-शुद्ध" के धागे का पालन करते हैं, जहां आप कार्यों को शुद्ध मॉडुलो मानते हैं तो कुछ अच्छी तरह से परिभाषित साइड-इफेक्ट्स हो सकते हैं। नकारात्मक पक्ष में आपका स्वागत। > :)
luqui

जवाबों:


185

नहीं यह नहीं। एक ही इनपुट को देखते हुए, यह फ़ंक्शन विभिन्न मान लौटाएगा। और फिर आप एक 'टेबल' नहीं बना सकते जो इनपुट और आउटपुट को मैप करता हो।

शुद्ध कार्य के लिए विकिपीडिया लेख से :

फ़ंक्शन हमेशा एक ही परिणाम मान का मूल्यांकन करता है जिसे समान तर्क मान दिया गया है। फ़ंक्शन परिणाम मान किसी भी छुपी हुई जानकारी या स्थिति पर निर्भर नहीं हो सकता है जो कार्यक्रम के निष्पादन के दौरान या कार्यक्रम के विभिन्न निष्पादन के बीच बदल सकता है, और न ही यह I / O उपकरणों से किसी भी बाहरी इनपुट पर निर्भर हो सकता है

इसके अलावा, एक और बात यह है कि एक शुद्ध फ़ंक्शन को एक तालिका से बदला जा सकता है जो इनपुट और आउटपुट से मैपिंग का प्रतिनिधित्व करता है, जैसा कि इस धागे में समझाया गया है ।

यदि आप इस फ़ंक्शन को फिर से लिखना चाहते हैं और इसे एक शुद्ध फ़ंक्शन में बदलना चाहते हैं, तो आपको एक तर्क के रूप में यादृच्छिक मान भी पास करना चाहिए

function test(random, min, max) {
   return random * (max - min) + min;
}

और फिर इसे इस तरह से कॉल करें (उदाहरण के लिए, 2 और 5 के रूप में न्यूनतम और अधिकतम):

test( Math.random(), 2, 5)

2
क्या होगा यदि आप कॉल करने से पहले फ़ंक्शन के अंदर हर बार यादृच्छिक जनरेटर को फिर से बीज कर रहे थे Math.random?
cs95

16
@ c @s-तब भी, यह अभी भी दुष्प्रभाव (भविष्य के Math.randomउत्पादन में परिवर्तन ) होगा; शुद्ध होने के लिए, आपको किसी तरह वर्तमान RNG राज्य को सहेजना होगा, इसे फिर से भेजना होगा, कॉल करना होगा Math.randomऔर इसे पिछली स्थिति में पुनर्स्थापित करना होगा।
२०:०६ पर लीजनमैमल

2
@ c @s around सभी गणना की गई RNG बेतरतीब बेतरतीबी के आसपास आधारित है। कुछ को नीचे की ओर चलाना पड़ता है जिसके कारण यह यादृच्छिक रूप से प्रकट होता है और आप इसे अपवित्र नहीं कर सकते। इसके अलावा, और शायद आपके प्रश्न के लिए अधिक महत्वपूर्ण, आप
zfrisch

14
@ LegionMammal978 ... और ऐसा परमाणु रूप से करते हैं।
वचर्जिन

2
@ c @ss RNG के ऐसे तरीके हैं जो शुद्ध कार्यों के साथ काम करते हैं, लेकिन इसमें फ़ंक्शन के लिए RNG स्टेट पास करना और फ़ंक्शन को रिप्लेसमेंट RNG स्टेट को वापस करना शामिल है, जो कि Haskell (एक कार्यात्मक प्रोग्रामिंग भाषा: कार्यात्मक शुद्धता को लागू करता है) प्राप्त करता है। यह।
छत्र

50

आपके प्रश्न का सरल उत्तर यह है कि Math.random()नियम # 2 का उल्लंघन है।

यहाँ कई अन्य उत्तरों ने बताया Math.random()है कि इस समारोह की उपस्थिति शुद्ध नहीं है। लेकिन मुझे लगता है कि यह कहने लायक है कि क्यों Math.random() टेंट कार्य करता है जो इसका उपयोग करते हैं।

सभी छद्म आयामी संख्या जनरेटर की तरह, Math.random()एक "बीज" मूल्य से शुरू होता है। यह उस मूल्य को निम्न-स्तरीय बिट जोड़तोड़ या अन्य संचालन की एक श्रृंखला के लिए शुरुआती बिंदु के रूप में उपयोग करता है जिसके परिणामस्वरूप अप्रत्याशित (लेकिन वास्तव में यादृच्छिक नहीं ) आउटपुट होता है।

जावास्क्रिप्ट में, शामिल प्रक्रिया कार्यान्वयन-निर्भर है, और कई अन्य भाषाओं के विपरीत, जावास्क्रिप्ट बीज का चयन करने का कोई तरीका प्रदान नहीं करता है :

कार्यान्वयन यादृच्छिक बीज पीढ़ी एल्गोरिदम के लिए प्रारंभिक बीज का चयन करता है; इसे उपयोगकर्ता द्वारा चुना या रीसेट नहीं किया जा सकता है।

इसलिए यह फ़ंक्शन शुद्ध नहीं है: जावास्क्रिप्ट अनिवार्य रूप से एक अंतर्निहित फ़ंक्शन पैरामीटर का उपयोग कर रहा है जिसका आपके पास कोई नियंत्रण नहीं है। यह उस पैरामीटर को उस डेटा से पढ़ रहा है, जिसकी गणना कहीं और की जाती है, और इसलिए आपकी परिभाषा में नियम # 2 का उल्लंघन होता है।

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

इस फ़ंक्शन के शुद्ध संस्करण को तीन पैरामीटर लेने की आवश्यकता होगी :

function test(min, max, seed) {
   return  seedable_random(seed) * (max - min) + min;
}

(min, max, seed)मापदंडों के किसी भी ट्रिपल के लिए , यह हमेशा एक ही परिणाम लौटाएगा।

ध्यान दें कि यदि आप आउटपुट seedable_randomको वास्तव में यादृच्छिक होना चाहते हैं , तो आपको बीज को यादृच्छिक बनाने का एक तरीका खोजना होगा! और जो भी रणनीति आपने इस्तेमाल की है वह अनिवार्य रूप से गैर-शुद्ध होगी, क्योंकि इसके लिए आपको अपने फ़ंक्शन के बाहर स्रोत से जानकारी एकत्र करने की आवश्यकता होगी। जैसा कि mtraceur और jpmc26 मुझे याद दिलाते हैं, इसमें सभी भौतिक दृष्टिकोण शामिल हैं: हार्डवेयर यादृच्छिक संख्या जनरेटर , लेंस कैप के साथ वेबकैम , वायुमंडलीय शोर संग्राहक - यहां तक ​​कि लावा लैंप भी । इन सभी में फ़ंक्शन के बाहर गणना और संग्रहीत डेटा का उपयोग करना शामिल है।


8
Math.random () न केवल इसके "बीज" को पढ़ता है, बल्कि इसे संशोधित भी करता है, ताकि अगली कॉल कुछ अलग लौटे। पर निर्भर करता है, और संशोधन, स्थिर राज्य निश्चित रूप से एक शुद्ध कार्य के लिए बुरा है।
नैट एल्ड्रेडगे

2
@ NateEldredge, बहुत बहुत! हालांकि केवल कार्यान्वयन-निर्भर मूल्य को पढ़ना शुद्धता को तोड़ने के लिए पर्याप्त है। उदाहरण के लिए, कभी ध्यान दें कि पायथन 3 हैश प्रक्रियाओं के बीच स्थिर कैसे नहीं हैं?
प्रेषक

2
यदि Math.randomPRNG का उपयोग नहीं किया जाता है, लेकिन हार्डवेयर RNG का उपयोग करने के बजाय इसे लागू किया जाता है तो यह उत्तर कैसे बदलेगा ? हार्डवेयर RNG वास्तव में सामान्य अर्थों में राज्य नहीं है, लेकिन यह यादृच्छिक मानों का उत्पादन करता है (और इस तरह फ़ंक्शन आउटपुट इनपुट की परवाह किए बिना अलग है), है ना?
mtraceur

@mtraceur, यह सही है। लेकिन मुझे नहीं लगता कि इसका जवाब ज्यादा बदलेगा। वास्तव में, यही कारण है कि मैं अपने उत्तर में "राज्य" के बारे में बात करने में समय नहीं बिताता। एक हार्डवेयर RNG से पढ़ने का मतलब "कहीं और गणना और संग्रहीत डेटा" से पढ़ना है। यह सिर्फ इतना है कि डेटा की गणना और कंप्यूटर के भौतिक माध्यम में ही संग्रहीत की जाती है क्योंकि यह अपने पर्यावरण के साथ बातचीत करता है।
प्रेषक

1
यही तर्क अधिक परिष्कृत यादृच्छिककरण योजनाओं पर भी लागू होता है, यहां तक ​​कि random.org जैसे वायुमंडलीय शोर पर भी । +1
jpmc26

38

एक शुद्ध फ़ंक्शन एक ऐसा फ़ंक्शन है जहां अवलोकन मूल्य केवल इसके इनपुट मूल्यों द्वारा निर्धारित किया जाता है, बिना अवलोकन साइड इफेक्ट्स के

Math.random का उपयोग करके, आप इनपुट मानों के अलावा किसी अन्य चीज़ से इसके मूल्य का निर्धारण कर रहे हैं। यह शुद्ध कार्य नहीं है।

स्रोत


25

नहीं, यह एक शुद्ध कार्य नहीं है क्योंकि इसका आउटपुट केवल प्रदान किए गए इनपुट पर निर्भर नहीं करता है (Math.random () किसी भी मूल्य को आउटपुट कर सकता है), जबकि शुद्ध कार्यों को हमेशा समान इनपुट के लिए समान मूल्य का उत्पादन करना चाहिए।

यदि कोई फ़ंक्शन शुद्ध है, तो एक ही इनपुट के साथ कई कॉल को ऑप्टिमाइज़ करना सुरक्षित है और पहले कॉल के परिणाम का पुन: उपयोग करें।

मेरे लिए PS कम से कम और कई अन्य लोगों के लिए, redux ने शुद्ध कार्य को लोकप्रिय बना दिया । Redux डॉक्स से सीधे :

वे चीजें जो आपको किसी रिड्यूसर के अंदर नहीं करनी चाहिए:

  • इसके तर्कों को म्यूट करें;

  • एपीआई कॉल और रूटिंग संक्रमण जैसे साइड इफेक्ट्स करें;

  • गैर-शुद्ध कार्यों को कॉल करें, जैसे Date.now () या Math.random ()।


3
हालाँकि अन्य लोगों ने शानदार उत्तर दिए हैं, लेकिन मैं खुद का विरोध नहीं कर सका जब मेरे दिमाग में
Redux

20

गणितीय दृष्टिकोण से, आपका हस्ताक्षर नहीं है

test: <number, number> -> <number>

परंतु

test: <environment, number, number> -> <environment, number>

जहां का environmentपरिणाम प्रदान करने में सक्षम है Math.random()। और वास्तव में यादृच्छिक मूल्य उत्पन्न करना पर्यावरण को एक पक्ष प्रभाव के रूप में उत्परिवर्तित करता है, इसलिए आप एक नया वातावरण भी लौटाते हैं, जो पहले वाले के बराबर नहीं है!

दूसरे शब्दों में, यदि आपको किसी भी प्रकार के इनपुट की आवश्यकता होती है, जो प्रारंभिक तर्कों ( <number, number>भाग) से नहीं आता है , तो आपको निष्पादन पर्यावरण के साथ प्रदान करने की आवश्यकता है (जो इस उदाहरण में राज्य के लिए प्रदान करता है Math)। यही बात अन्य उत्तरों द्वारा उल्लिखित अन्य बातों पर भी लागू होती है, जैसे I / O या ऐसी।


सादृश्य के रूप में, आप यह भी नोटिस कर सकते हैं कि ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग का प्रतिनिधित्व कैसे किया जा सकता है - अगर हम कहते हैं, जैसे

SomeClass something
T result = something.foo(x, y)

तब वास्तव में हम उपयोग कर रहे हैं

foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>

जिस वस्तु के साथ इसकी विधि को लागू किया गया है वह पर्यावरण का हिस्सा है। और SomeClassपरिणाम का हिस्सा क्यों ? क्योंकि somethingराज्य बदल सकता था!


7
इससे भी बदतर अभी तक, पर्यावरण भी उत्परिवर्तित है, इसलिए test: <environment, number, number> -> <environment, number>यह होना चाहिए
Bergi

1
मुझे यकीन नहीं है कि OO उदाहरण बहुत समान है। के प्रकार के आधार पर अतिभारित परिभाषाओं को दूर करने के लिए एक विशेष नियम के साथ a.F(b, c)सिंटैक्टिक चीनी के रूप में देखा जा सकता है (यह वास्तव में है कि पायथन इसका प्रतिनिधित्व कैसे करता है)। लेकिन दोनों संकेतन में अभी भी स्पष्ट है, जबकि स्रोत कोड में एक गैर-शुद्ध फ़ंक्शन में पर्यावरण का उल्लेख कभी नहीं किया जाता है। F(a, b, c)Faa
IMSoP

11

शुद्ध कार्य हमेशा समान इनपुट के लिए समान मान लौटाते हैं। शुद्ध कार्य पूर्वानुमेय हैं और संदर्भित करने योग्य पारदर्शी हैं जिसका अर्थ है कि हम फ़ंक्शन कॉल को बदले गए आउटपुट से बदल सकते हैं और यह प्रोग्राम के काम को नहीं बदलेगा।

https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md


10

अन्य उत्तरों के अलावा जो सही ढंग से इंगित करते हैं कि यह फ़ंक्शन गैर-नियतात्मक कैसे है, इसका एक साइड-इफेक्ट भी है: यह भविष्य के कॉल को math.random()एक अलग उत्तर देने का कारण होगा । और एक यादृच्छिक-संख्या जनरेटर जिसके पास वह संपत्ति नहीं है वह आम तौर पर कुछ प्रकार के I / O का प्रदर्शन करेगा, जैसे कि OS द्वारा प्रदान किए गए यादृच्छिक उपकरण से पढ़ना। या तो शुद्ध कार्य के लिए वर्बोटेन है।


7

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

function test(min, max, generator) {
  return  generator() * (max - min) + min;
}

अब, आप जनरेटर का मजाक उड़ा सकते हैं और अपने कोड का ठीक से परीक्षण कर सकते हैं:

const result = test(1, 2, () => 3);
result == 4 //always true

और आपके "उत्पादन" कोड में:

const result = test(1, 2, Math.random);

1
। परीक्षणशीलता के लिए अपने विचार के लिए। थोड़ी देखभाल के साथ आप एक स्वीकार करते समय भी दोहराए जाने वाले परीक्षण का उत्पादन कर सकते हैं util.Random, जिसे आप पुराने व्यवहार को दोहराने के लिए या एक नए (लेकिन दोहराने योग्य) रन के लिए टेस्ट रन की शुरुआत में बीज कर सकते हैं। यदि मल्टी-थ्रेडिंग है, तो आप इसे मुख्य थ्रेड में करने में सक्षम हो सकते हैं और इसका उपयोग Randomरिपीटेबल थ्रेड-लोकल Randomएस को सीड करने में कर सकते हैं । हालाँकि, जैसा कि मैं इसे समझता हूं, इसे test(int,int,Random)शुद्ध नहीं माना जाता क्योंकि यह राज्य की स्थिति को बदल देता है Random
PJTraill

2

क्या आप निम्नलिखित के साथ ठीक होंगे:

return ("" + test(0,1)) + test(0,1);

के बराबर हो

var temp = test(0, 1);
return ("" + temp) + temp;

?

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

मुझे इसके साथ व्यावहारिक अनुभव है। SQL सर्वर ने अनुमति दी है getdate()और newid()"शुद्ध" कार्यों में और ऑप्टिमाइज़र इच्छानुसार कॉल काट देगा। कभी-कभी यह कुछ गूंगा हो जाता।

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