2012-05-09 24 views
7

मैं bcmath विस्तार के लिए एक आवरण लिख रहा हूँ, और bug #10116bcpow() के बारे में विशेष रूप से परेशान है - यह $right_operand ($exp) एक (देशी पीएचपी करने के लिए, नहीं मनमाने ढंग से लंबाई डाले) पूर्णांक, इसलिए जब आप किसी संख्या के वर्ग रूट (या 1 से अधिक किसी अन्य रूट की गणना करने का प्रयास करते हैं) तो आप हमेशा सही परिणाम के बजाय 1 के साथ समाप्त होते हैं।गिना जा रहा है फ्लोटिंग प्वाइंट शक्तियों (PHP/BCMath)

मैं एल्गोरिदम है कि मुझे एक नंबर के n वीं मूल और मैं found this answer जो बहुत ठोस लग रहा है की गणना करने की अनुमति होगी के लिए खोज शुरू कर दिया, मैं वास्तव में expanded the formula का उपयोग कर वॉलफ्रेम अल्फा और मैं जबकि सटीकता रखने के बारे में 5% से यह गति है में सुधार करने में सक्षम था परिणाम के।

यहाँ एक शुद्ध पीएचपी मेरी BCMath कार्यान्वयन और अपनी सीमाएं नकल उतार दिया गया है:

function _pow($n, $exp) 
{ 
    $result = pow($n, intval($exp)); // bcmath casts $exp to (int) 

    if (fmod($exp, 1) > 0) // does $exp have a fracional part higher than 0? 
    { 
     $exp = 1/fmod($exp, 1); // convert the modulo into a root (2.5 -> 1/0.5 = 2) 

     $x = 1; 
     $y = (($n * _pow($x, 1 - $exp))/$exp) - ($x/$exp) + $x; 

     do 
     { 
      $x = $y; 
      $y = (($n * _pow($x, 1 - $exp))/$exp) - ($x/$exp) + $x; 
     } while ($x > $y); 

     return $result * $x; // 4^2.5 = 4^2 * 4^0.5 = 16 * 2 = 32 
    } 

    return $result; 
} 

ऊपर seems to work greatको छोड़कर जब 1/fmod($exp, 1) एक पूर्णांक उपज नहीं है। उदाहरण के लिए, यदि $exp0.123456 है, इसका उलटा 8.10005 और pow() और _pow() के परिणाम होगा कुछ अलग (demo) हो जाएगा:

  • pow(2, 0.123456) = 1.0893412745953
  • _pow(2, 0.123456) = 1.0905077326653
  • _pow(2, 1/8) = _pow(2, 0.125) = 1.0905077326653

"मैनुअल" घातीय गणनाओं का उपयोग करके मैं समान स्तर की सटीकता कैसे प्राप्त कर सकता हूं?

+1

यह बिल्कुल के रूप में विज्ञापित काम कर रहा है उपयोग करने के लिए है। निकटतम '1/n' के लिए आंशिक भाग '_pow'' राउंड '। आप इस काम को बार-बार कर सकते हैं। तो '_pow (2, 0.125)' की गणना करने के बाद, आप '_pow (2,0.125-123456) 'की गणना करते हैं और इसी तरह। –

+1

आह, अब मैं समझता हूं। तो bcmath में 'exp' और' log' नहीं है या अन्य कारण हैं कि 'a^b = exp (b * log (a)) 'कोई विकल्प नहीं है? रिकर्सन जेफरी का सुझाव है कि निश्चित रूप से काम करेगा, लेकिन अगर आपको एक्सपोनेंट का प्रतिनिधित्व करने के लिए कई '1/के' की ज़रूरत है तो इसकी गति संतोषजनक नहीं हो सकती है। एक्सपोनेंट को तर्कसंगत संख्या 'एन/डी' के रूप में लिख रहा है और' (ए^एन)^(1/डी) 'एक विकल्प की गणना कर रहा है, या बहुत बड़ी' n' और 'd' की अपेक्षा की जानी चाहिए? शायद एक जांच के लायक एक तर्कसंगत संख्या द्वारा एक्सपोनेंट को अनुमानित कर रहा है जिसमें छोटे डिमॉमिनेटर (निरंतर अंश विस्तार) और बाकी के साथ रिकर्सन किया जा रहा है। –

+0

@ जेफरी सैक्स: आह, मैं देखता हूं ... यह एक बमर है लेकिन अभी भी काम नहीं कर रहा है (http://codepad.org/eI4ykyQU) या क्या मुझे कुछ याद आ रही है? –

उत्तर

5

कार्यरत एल्गोरिथ्म n वें एक (सकारात्मक) संख्या a की जड़ खोजने के लिए,

f(x) = x^n - a. 

घातांक के रूप में प्राकृतिक संख्या के साथ ही शक्तियां शामिल है कि के शून्य को खोजने के लिए न्यूटन एल्गोरिथ्म है इसलिए है लागू करने के लिए सीधा।

एक प्रतिपादक 0 < y < 1 जहां y एक पूर्णांक n अधिक जटिल है के साथ प्रपत्र 1/n की नहीं है के साथ एक बिजली की गणना करना। , एनालॉग कर

x^(1/y) - a == 0 

सुलझाने फिर गैर अभिन्न प्रतिपादक, बहुत समस्या हम हल करने के लिए कोशिश कर रहे हैं के साथ एक बिजली की गणना शामिल होगा।

हैं y = n/d छोटे भाजक d साथ तर्कसंगत है, समस्या को आसानी से की गणना

x^(n/d) = (x^n)^(1/d), 

द्वारा लेकिन सबसे तर्कसंगत 0 < y < 1, अंश और हर के लिए हल किया जाता है कर रहे हैं बल्कि बड़े, और मध्यवर्ती x^n विशाल होगा, इसलिए गणना बहुत सारी मेमोरी का उपयोग करेगी और एक (अपेक्षाकृत) लंबा समय लेगी। है

y = 1/a ± 1/b ± 1/c ± ... ± 1/q 
पूर्णांकों a < b < c < ... < q साथ

लिखने के लिए (0.123456 = 1929/15625 का उदाहरण प्रतिपादक के लिए, यह बहुत बुरा नहीं है, लेकिन 0.1234567 कर लगाने के बजाय होगा।)

एक तरह से सामान्य तर्कसंगत 0 < y < 1 के लिए बिजली की गणना करने के लिए और व्यक्तिगत x^(1/k) को गुणा/विभाजित करने के लिए। (हर तर्कसंगत 0 < y < 1 ऐसे अभ्यावेदन जैसे

1929/15625 = 1/8 - 1/648 - 1/1265625; 

केवल अतिरिक्त का उपयोग करने में अपघटन बड़ा हरों के साथ लंबे समय तक अभ्यावेदन की प्राप्ति होती है, और कम से कम इस तरह के निरूपण आम तौर पर कई मामले शामिल नहीं है, जैसे

1929/15625 = 1/9 + 1/82 + 1/6678 + 1/46501020 + 1/2210396922562500, 

ताकि इसमें अधिक काम शामिल हो।)

दृष्टिकोणों को मिलाकर कुछ सुधार संभव है, पहले y पर छोटे संप्रदाय वी के साथ एक करीबी तर्कसंगत अनुमान प्राप्त करें। 12 y का निरंतर अंश विस्तार उदाहरण के लिए एक्सपोनेंट 1929/15625 = [0;8,9,1,192] और पहले चार आंशिक उद्धरणों का उपयोग करके अनुमान 10/81 = 0.123456790123... [नोट करें कि 10/81 = 1/8 - 1/648, शुद्ध अंशों में सबसे कम अपघटन का आंशिक रकम अभिसरण हैं] - और फिर शेष को शुद्ध में विघटित करें अंशों।

हालांकि, आमतौर पर कि दृष्टिकोण बड़े n के लिए n वें जड़ों की गणना है, जो भी धीमी गति से और स्मृति गहन है अगर अंतिम परिणाम की वांछित सटीकता अधिक है की ओर जाता है।

कुल मिलाकर, यह शायद आसान है और तेजी से exp और log को लागू करने और

x^y = exp(y*log(x)) 
+0

महान, विस्तृत उत्तर! धन्यवाद। –

संबंधित मुद्दे