2016-12-12 3 views
6

में लिखे गए एक फैक्टोरियल फ़ंक्शन का कम प्रदर्शन मैं क्लोजर के लिए नया हूं। इसके प्रयोग में मैंने लिखा है कि मैं n! की गणना करने के लिए कार्य करता हूं। मेरा क्लोजर कोड निम्नानुसार है:क्लोजर

(defn factorial 
    [n] 
    (reduce * (biginteger 1) (range 1 (inc n)))) 

फिर मैंने एक प्रतिलिपि में निम्नलिखित भाग लिया।

(time (factorial 100)) 

और यह परिणाम था:

"Elapsed time: 0.50832 msecs" 
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000N 

मैं तो रूबी में एक ऐसी ही समाधान बनाया:

It took: 0.06556510925292969 msecs 
=> 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 
:

def factorial(n) 
    start = Time.now.to_f 
    (2..n).inject(1) { |p, f| p * f } 
    finish = Time.now.to_f 
    time_taken = finish - start 
    puts "It took: #{(time_taken * 1000)} msecs" 
end 

आईआरबी मैं factorial(100) भाग गया जिसके परिणामस्वरूप

रूबी संस्करण का प्रदर्शन काफी अधिक प्रतीत होता है, हालांकि मैंने देखा है कि क्लोजर में बेहतर प्रदर्शन होना चाहिए। क्या मुझे कुछ गलतफहमी है या मेरे क्लोजर समाधान का कुछ तत्व है जो इसे धीमा कर देगा?

+1

उपयोग करने का प्रयास को बढ़ावा देंगे '' बजाय biginteger' की bigint'। – ndn

+0

हाँ, जिसने बिगिनमेंट का काम किया, निष्पादन को बहुत तेज बना दिया। –

+0

इस बेंचमार्क में 'टाइम' का उपयोग करना गंभीर रूप से भ्रामक है क्योंकि JVM "warms up" फ़ंक्शन कैसे करता है। क्लोजर उदाहरण वास्तव में रूबी की तुलना में * अधिक * तेज है, बशर्ते आप जावा प्लेटफ़ॉर्म डिज़ाइनर को "तेज़" की परिभाषा स्वीकार करें, "संकलित होने के लिए पर्याप्त गर्म हो जाने के बाद" –

उत्तर

2

Miro-बेंच मार्किंग बहुत बार भ्रामक है और सामान्य रूप से यह यह सही पाने के लिए नहीं बल्कि मुश्किल है:

आप टाइप इशारा तर्क n द्वारा आगे की गति हासिल कर सकते हैं। सबसे आसान तरीका है यथोचित clojure में करीब पाने के लिए (है कि मैं मिल गया है (criterium पुस्तकालय है धन्यवाद ह्यूगो!)। मैं बस मैं के बारे में 3 एनएस मिल पाशन द्वारा भाज्य की गणना के एक बदसूरत संस्करण के साथ शुरू करते हैं।

user> (defn loopy-fact [x] 
     (loop [y x 
       answer-so-far 1] 
      (if (pos? y) 
      (recur (dec y) (*' answer-so-far y)) 
      answer-so-far))) 
#'user/loopy-fact 

user> (loopy-fact 100) 
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000N 

और यह बेंचमार्क तो चलो:

user> (criterium.core/bench #(loopy-fact 100)) 
WARNING: Final GC required 11.10521514596218 % of runtime 
WARNING: Final GC required 1.069604210579865 % of runtime 
Evaluation count : 12632130300 in 60 samples of 210535505 calls. 
      Execution time mean : 2.978360 ns 
    Execution time std-deviation : 0.116043 ns 
    Execution time lower quantile : 2.874266 ns (2.5%) 
    Execution time upper quantile : 3.243399 ns (97.5%) 
        Overhead used : 1.844334 ns 

Found 4 outliers in 60 samples (6.6667 %) 
    low-severe 2 (3.3333 %) 
    low-mild  2 (3.3333 %) 
Variance from outliers : 25.4468 % Variance is moderately inflated by outliers 

हम तो कोड करते हैं, तो एक सामान्य Clojure शैली का उपयोग करके बेहतर दिखेगा मानचित्र और कम करने, और यह तेजी से बनाने में कोई प्रयास के साथ।

user> (defn mapy-fact [x] 
     (reduce *' (range 1 (inc x))) 
#'user/mapy-fact 

user> (mapy-fact 100) 
933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000N 

अब चलो पता है कि कैसे तुलना करते हैं:

user> (criterium.core/bench #(mapy-fact 100)) 
Evaluation count : 8674569060 in 60 samples of 144576151 calls. 
      Execution time mean : 5.208031 ns 
    Execution time std-deviation : 0.265287 ns 
    Execution time lower quantile : 5.032058 ns (2.5%) 
    Execution time upper quantile : 5.833466 ns (97.5%) 
        Overhead used : 1.844334 ns 

Found 4 outliers in 60 samples (6.6667 %) 
    low-severe 1 (1.6667 %) 
    low-mild  3 (5.0000 %) 
Variance from outliers : 36.8585 % Variance is moderately inflated by outliers 

यह थोड़ा धीमा है, लेकिन केवल दो नैनोसेकंड से धीमी है।

यह आपके परीक्षण में दिखने से काफी बेहतर है क्योंकि मानदंड JVM के हॉटस्पॉट कंपाइलर के लिए पर्याप्त समय तक काम करता है ताकि इसे संकलित करने और सभी भागों को रेखांकित करने के लिए पर्याप्त समय मिल सके। यह दर्शाता है कि क्यों माइक्रोबेंचमार्क JVM पर बहुत भ्रामक हो सकता है। और आपको लगभग निश्चित रूप से ऐसे मामलों के लिए मानदंड रखना चाहिए।

पुनश्च: *' "ऑटो को बढ़ावा देने के" गुणा opperator है, यह यह बड़े पूर्णांक या बड़े दशमलव के प्रकार है के रूप में आवश्यक

6

BigInteger जावा से आता है, जबकि BigInt क्लोजर के कोर में लागू किया गया है। बल्ले से बाहर, यह interopability से संबंधित कुछ लागतों के साथ आता है।


साथ ही, BigInt या तो a long or a BigInteger के रूप में प्रतिनिधित्व किया है। जब भी संभव हो, the long is used। हालांकि, अगर कोई ऑपरेशन overflow बनाता है, परिणामी नया BigIntwill use it's BigInteger। जावा के long मूल आर्किटेक्चर के कार्यान्वयन के लिए नक्शे, इसलिए काफी तेज़ है। यह Fixnum और Bignum के बीच रूबी के जादू रूपांतरण के समान है।

चूंकि आप लगभग विशेष रूप से छोटी संख्याओं का उपयोग करते हैं (1 से 100 और मध्यवर्ती उत्पादों का एक अच्छा हिस्सा), तो आप एक महत्वपूर्ण प्रदर्शन को बढ़ावा दे सकते हैं।

+2

मुझे उपयोग के बीच अंतर पर चर्चा करने का उत्तर मिला biginteger और bigint http://stackoverflow.com/a/18024386/2801159 –

+0

@Travismith, अच्छा, अपडेट किया गया। टाइपिंग संकेत के साथ – ndn

2
@ndn's answer को आगे

:

(defn factorial [^long n] 
    (reduce * (bigint 1) (range 1 (inc n)))) 
+0

मुझे रनटाइम मिलता है: 'निष्पादन समय का मतलब: 5.197206 एनएस' और बिना मुझे निष्पादन समय का मतलब है: 5.349130 एनएस' 0.34 एनएस के मानक विचलन के साथ, इसलिए प्रकार संकेत द्वारा किए गए अंतर शोर में हैं । ऐसा इसलिए है क्योंकि क्लोजर कंपाइलर टाइप अनुमान लगाता है और इसे स्वयं ही समझता है। –

+0

@AththurUlfeldt क्लोजर कंपाइलर यह नहीं जान सकता कि 'n' एक पूर्ण संख्या है, क्योंकि इसकी आवश्यकता नहीं है। क्या यह अधिक संभावना नहीं है कि हॉटस्पॉट अच्छा काम कर रहा है? – Thumbnail