2013-08-19 5 views
11

पर "अधिकतम कॉल स्टैक आकार पार हो गया" त्रुटियों को हल करने के लिए मुझे बहुत विशाल सरणी का अधिकतम और न्यूनतम मान मिलना है। इसके लिए मैंक्रोम: Math.max.apply (Math, array)

Math.max.apply(Math, my_array); 
Math.min.apply(Math, my_array); 

यह Firefox और IE पर अच्छा काम करता है का उपयोग कर रहा है, लेकिन क्रोम पर मैं हमेशा Maximum call stack size exceeded त्रुटियों मिलता है ... मेरे वर्तमान सरणी 221,954 तत्व है, और कहा कि मेरा सबसे बड़ा नहीं है।

क्या कोई जानता है कि क्रोम पर इस त्रुटि को कैसे हल किया जाए? मैं अधिकतम और न्यूनतम मूल्य की खोज कैसे अनुकूलित कर सकता हूं?

उन लोगों को जो विश्वास नहीं कर सकता, क्रोम के कंसोल में इस कोशिश के लिए:

var xxx = [] 
for(var i=0; i<300000; i++){ 
    xxx.push(Math.random()); 
} 
Math.max.apply(Math, xxx); 

---> RangeError: अधिकतम कॉल स्टैक आकार से अधिक हो

+0

आप इस प्रश्न पर एक नज़र डालना चाहेंगे: http://stackoverflow.com/questions/1669190/javascript-min-max-array-values ​​ –

+0

मैंने इसे देखा। वहां से मैंने अपनी दो पंक्तियों की प्रतिलिपि बनाई। लेकिन मेरी समस्या के बारे में कुछ भी नहीं है ... – PanChan

+0

नीचे स्क्रॉल करने का प्रयास करें: http://stackoverflow.com/a/13440842/2074608 –

उत्तर

0

मेरे लिए त्रुटि नहीं करना चाहिए कॉल से Math.min/max में आते हैं यह रिकर्सन का उपयोग करने के परिणाम की तरह दिखता है जिसे मैं निष्क्रिय नहीं कर सकता क्रोम उन कार्यों को लागू करने के लिए उपयोग करेगा।

क्या वे रिकर्सिव कोड में एम्बेड किए गए हैं?

आप क्रोम में समस्या से बचने के लिए अपने स्वयं के न्यूनतम/अधिकतम कोड को छोटे से रोल कर सकते हैं।

+0

क्रोम में डिबगिंग करते समय, यह हमेशा 'Math.max.apply' के साथ लाइन पर रुक जाता है, मैं भी इसे विश्वास नहीं कर सका, लेकिन यह सच है ... और मेरे पास इस कोड में कोई रिकर्सन नहीं है। ये दो रेखाएं एक इनिट-फ़ंक्शन में हैं जिन्हें केवल एक बार बुलाया जाता है। – PanChan

0
var a=[]; 
for(var i=0;i<1125011;i++){ 
    a[i] = i; 
} 
function maxIterate(arr){ 
    var max = arr[0]; 
    for(var i = 1;i< arr.length; i++){ 
     (max < arr[i]) && (max = arr[i]) 
    } 
    return max; 
} 
console.log(maxIterate(a)); 

Math.max अधिकतम मूल्य प्राप्त करने के पुनरावर्ती विधि का उपयोग कर सकते हैं, बस एक बार दोहराना समारोह को फिर से लिखने अधिकतम instead.This पाने के लिए RangeError से बचने जाएगा।

+0

क्या? (अधिकतम

+0

@ लुकास.pukenis - यह संचालन का आदेश है। यदि अधिकतम

1

आप फ़ंक्शन पैरामीटर आकार सीमा तक पहुंच रहे हैं। और यह ठीक है। फ़ंक्शन को केवल कुछ पैरामीटर स्वीकार करना चाहिए क्योंकि कोड गंध है।

यदि आपके पास आइटम का एक गुच्छा है? - ऐरे का प्रयोग करें। आप .apply() का उपयोग कर रहे हैं जो से गुजरता है जैसे fun(1,2,3,4,5,6....) और सीमा तक पहुंचता है। यह खराब अभ्यास है।

समस्या यह है - Math.max() केवल इस तरह काम करने के लिए वायर्ड है, इसलिए आपकी सर्वश्रेष्ठ शर्त पुनरावृत्ति खोज फ़ंक्शन होगी। लेकिन यह एक और विषय है, क्योंकि प्रदर्शन और एल्गोरिदम उदाहरण के लिए भिन्न हो सकता है यदि आप पहले सरणी को सॉर्ट करते हैं।

+4

यह कुछ elitist बैल है। परिवर्तनीय मात्रा तर्क का उपयोग जावास्क्रिप्ट लचीलापन के चमत्कारों में से एक है। ऐसा करने की ज़रूरत नहीं है! यह कई मामलों में बहुत सुविधाजनक है। आपको बुरा होने का कारण देना चाहिए! – Lodewijk

+1

मुझे यह पसंद है और इसका इस्तेमाल करें। इसके अलावा मैं उत्तर में किनारे के मामलों के बारे में हूं :) –

17

इस समस्या में विशेष रूप से Math.max और Math.min के साथ कुछ भी करने के लिए कुछ भी नहीं है।

फ़ंक्शन.प्रोटोटाइप.एप्ली केवल अपने दूसरे तर्क के रूप में सीमित लंबाई की सरणी प्राप्त कर सकता है।

function limit(l) { 
    var x = []; x.length = l; 
    (function(){}).apply(null, x); 
} 

स्थानीय स्तर पर, सीमा (एल) एल के साथ वास्तव में दुर्घटनाग्रस्त हो गया = 124980. कनारी में, कि एक और नंबर था ~ 125k, लेकिन यह भी:

स्थानीय स्तर पर, मैं इसे क्रोम में का उपयोग कर परीक्षण किया गया।

यह एक उदाहरण है कि ऐसा क्यों होता है: https://code.google.com/p/v8/issues/detail?id=2896 (यह अन्य जेएस इंजनों में भी पुन: प्रयोज्य है, उदाहरण के लिए एमडीएन में इस मुद्दे का उल्लेख है: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions ("लेकिन सावधान रहें ...") से संकेत मिलता है वेबकिट बगजिला में यह समस्या: https://bugs.webkit.org/show_bug.cgi?id=80797)।जहां तक ​​मुझे समझ में आता है कि V8:

V8 असेंबली में Function.prototype.apply लागू करता है। फ़ंक्शन को कॉल करने से पहले, इसे सभी फ़ंक्शन कॉल पैरामीटर रखना चाहिए, उदा। जावास्क्रिप्ट फ़ंक्शन को कॉल करने से पहले, इस आर्ग, और दूसरे तर्क सरणी के सभी सदस्यों, एक द्वारा स्टैक पर। लेकिन ढेर में सीमित क्षमता है, और यदि आप सीमा को दबाते हैं, तो आपको रेंजरर मिल जाएगा।

यह है कि मैं क्या वी 8 स्रोत (IA-32 विधानसभा, builtins-ia32.cc) में पाया गया है:

void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 
    static const int kArgumentsOffset = 2 * kPointerSize; 
    static const int kReceiverOffset = 3 * kPointerSize; 
    static const int kFunctionOffset = 4 * kPointerSize; 
    { 
    FrameScope frame_scope(masm, StackFrame::INTERNAL); 

    __ push(Operand(ebp, kFunctionOffset)); // push this 
    __ push(Operand(ebp, kArgumentsOffset)); // push arguments 
    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 

    // Check the stack for overflow. We are not trying to catch 
    // interruptions (e.g. debug break and preemption) here, so the "real stack 
    // limit" is checked. 
    Label okay; 
    ExternalReference real_stack_limit = 
     ExternalReference::address_of_real_stack_limit(masm->isolate()); 
    __ mov(edi, Operand::StaticVariable(real_stack_limit)); 
    // Make ecx the space we have left. The stack might already be overflowed 
    // here which will cause ecx to become negative. 
    // !! ADDED COMMENT: IA-32 stack grows downwards, if address to its current top is 0 then it cannot be placed any more elements into. esp is the pointer to stack top. 
    __ mov(ecx, esp); 
    // !! ADDED COMMENT: edi holds the "real_stack_limit", which holds the minimum address that stack should not grow beyond. If we subtract edi from ecx (=esp, or, in other words, "how much space is left on the stack"), we may get a negative value, and the comment above says that 
    __ sub(ecx, edi); 
    // Make edx the space we need for the array when it is unrolled onto the 
    // stack. 
    // !! ADDED COMMENT: eax holds the number of arguments for this apply call, where every member of the 2nd argument array counts as separate argument 
    __ mov(edx, eax); 
    // !! ADDED COMMENT: kPointerSizeLog2 - kSmiTagSize is the base-2-logarithm of how much space would 1 argument take. By shl we in fact get 2^(kPointerSizeLog2 - kSmiTagSize) * arguments_count, i.e. how much space do actual arguments occupy 
    __ shl(edx, kPointerSizeLog2 - kSmiTagSize); 
    // Check if the arguments will overflow the stack. 
    // !! ADDED COMMENT: we compare ecx which is how much data we can put onto stack with edx which now means how much data we need to put onto stack 
    __ cmp(ecx, edx); 
    __ j(greater, &okay); // Signed comparison. 

    // Out of stack space. 
    __ push(Operand(ebp, 4 * kPointerSize)); // push this 
    __ push(eax); 
    __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 

कृपया जांच करें !! मैं इसे कैसे समझता हूं इसके स्पष्टीकरण के लिए टिप्पणी जोड़ा।

और यह APPLY_OVERFLOW समारोह, जे एस में लिखा (फिर से, वी 8 स्रोत, runtime.js) है:

function APPLY_OVERFLOW(length) { 
    throw %MakeRangeError('stack_overflow', []); 
} 

संपादित करें: आपके मामले में, मैं जाना होगा जैसे:

var max = -Infinity; 
for(var i = 0; i < arr.length; i++) if (arr[i] > max) max = arr[i]; 
+1

मेरे मामले में, निम्न कार्य की सीमा 251100 (ताजा शुरुआत पर) है: 'फ़ंक्शन अधिकतम (एआर) {वापसी Math.max.apply (शून्य, arr); } ' –