सारांश संपादित करें
- मेरे मूल उत्तर में केवल इस बात का उल्लेख किया गया था कि इस कोड में बहुत सारी प्रतिरूपित गणनाएँ थीं और कई शक्तियों में 1/3 के कारक शामिल थे। उदाहरण के लिए, के
pow(x, 0.1e1/0.3e1)
रूप में ही है cbrt(x)
।
- मेरा दूसरा सम्पादन सिर्फ गलत था, और मेरी तीसरी गलती इस पर हुई। यह वही है जो लोग 'एम' अक्षर से शुरू होने वाले प्रतीकात्मक गणित कार्यक्रमों से ओरेकल जैसे परिणामों को बदलने से डरते हैं। मैंने उन एडिट्स को
स्ट्राइक (यानी, स्ट्राइक ) किया है और उन्हें इस उत्तर के वर्तमान संशोधन के निचले हिस्से में धकेल दिया है। हालाँकि, मैंने उन्हें नहीं हटाया। मैं मानव हूं। हमारे लिए गलती करना आसान है।
- मेरे चौथे संपादन ने एक बहुत ही कॉम्पैक्ट अभिव्यक्ति विकसित की है जो प्रश्न में जटिल अभिव्यक्ति का सही प्रतिनिधित्व करती है यदि मानकों
l1
, l2
, और l3
सकारात्मक वास्तविक संख्या हैं और अगर a
एक गैर शून्य वास्तविक संख्या है। (हम अभी तक इन गुणांक की विशिष्ट प्रकृति के बारे में ओपी से सुनना चाहते हैं। समस्या की प्रकृति को देखते हुए, ये उचित धारणाएं हैं।)
- यह इन समस्याओं को सरल बनाने की सामान्य समस्या का जवाब देने का प्रयास करता है।
पहली चीजें पहले
मैं गलतियों से बचने के लिए C ++ कोड उत्पन्न करने के लिए मेपल का उपयोग करता हूं।
मेपल और गणितज्ञ कभी-कभी स्पष्ट याद करते हैं। इससे भी महत्वपूर्ण बात यह है कि मेपल और गणितज्ञ के उपयोगकर्ता कभी-कभी गलतियाँ करते हैं। "कभी-कभी" के स्थान पर "अक्सर", या शायद यहां तक कि "लगभग हमेशा" के स्थान पर, शायद कभी-कभी निशान के करीब होता है।
आप मेपल को सवाल में मापदंडों के बारे में बताकर उस अभिव्यक्ति को सरल बनाने में मदद कर सकते थे। उदाहरण के लिए, मुझे संदेह है कि l1
, l2
और l3
सकारात्मक वास्तविक संख्याएं हैं और a
यह एक गैर-शून्य वास्तविक संख्या है। अगर ऐसा है, तो इसे बताएं। वे प्रतीकात्मक गणित कार्यक्रम आमतौर पर मान लेते हैं कि हाथ जटिल हैं। डोमेन को प्रतिबंधित करने से प्रोग्राम को ऐसी धारणाएँ बनाने में मदद मिलती है जो जटिल संख्याओं में मान्य नहीं हैं।
सांकेतिक गणित कार्यक्रमों से उन बड़ी गड़बड़ियों को कैसे सरल बनाया जाए (यह संपादित करें)
प्रतीकात्मक गणित कार्यक्रम आम तौर पर विभिन्न मापदंडों के बारे में जानकारी प्रदान करने की क्षमता प्रदान करते हैं। उस क्षमता का उपयोग करें, खासकर यदि आपकी समस्या में विभाजन या घातांक शामिल है। हाथ में उदाहरण में, आप मेपल यह कह रही है कि द्वारा कि अभिव्यक्ति को आसान बनाने में मदद की सकता है l1
, l2
और l3
कर रहे हैं सकारात्मक वास्तविक संख्या और कहा कि a
एक गैर शून्य वास्तविक संख्या है। अगर ऐसा है, तो इसे बताएं। वे प्रतीकात्मक गणित कार्यक्रम आमतौर पर मान लेते हैं कि हाथ जटिल हैं। डोमेन को प्रतिबंधित करने से प्रोग्राम को x b x = (ab) x जैसे अनुमान लगाने की सुविधा मिलती है । यह तभी है a
और b
सकारात्मक वास्तविक संख्या हैं और अगर x
वास्तविक है। यह जटिल संख्याओं में मान्य नहीं है।
अंततः, वे प्रतीकात्मक गणित कार्यक्रम एल्गोरिदम का पालन करते हैं। इसके साथ मदद करें। कोड जनरेट करने से पहले विस्तार, संग्रह, और सरलीकरण के साथ खेलने का प्रयास करें। इस मामले में, आप उन शर्तों को एकत्र कर सकते हैं जिनमें एक कारक शामिल होता है mu
और एक कारक शामिल होता है K
। अपने "सरलतम रूप" के लिए एक अभिव्यक्ति को कम करना एक कला का एक सा रहता है।
जब आपको उत्पन्न कोड की बदसूरत गड़बड़ मिलती है, तो इसे एक सच्चाई के रूप में स्वीकार न करें जिसे आपको स्पर्श नहीं करना चाहिए। इसे स्वयं सरल बनाने का प्रयास करें। यह देखें कि सांकेतिक गणित कार्यक्रम कोड उत्पन्न करने से पहले क्या था। देखो कि कैसे मैंने आपकी अभिव्यक्ति को बहुत सरल और बहुत तेज़ी से कम किया, और वाल्टर के जवाब ने मुझे कई कदम आगे बढ़ाया। कोई जादुई नुस्खा नहीं है। अगर कोई जादुई नुस्खा होता, तो मेपल ने उसे लागू कर दिया होता और वाल्टर ने जो जवाब दिया था।
विशिष्ट प्रश्न के बारे में
आप उस गणना में बहुत अधिक जोड़ और घटाव कर रहे हैं। यदि आपके पास शर्तें हैं कि आप एक दूसरे को रद्द कर सकते हैं, तो आप मुश्किल में पड़ सकते हैं। यदि आपके पास एक शब्द है जो दूसरों पर हावी है, तो आप बहुत सारे सीपीयू बर्बाद कर रहे हैं।
अगला, आप बार-बार गणना करके बहुत सारे सीपीयू बर्बाद कर रहे हैं। जब तक आपने सक्षम नहीं किया है -ffast-math
, जो कंपाइलर को IEEE फ्लोटिंग पॉइंट के कुछ नियमों को तोड़ने देता है, तो कंपाइलर आपके लिए उस एक्सप्रेशन को सरल नहीं करेगा। यह बदले में वही करेगा जो आपने इसे करने के लिए कहा था। कम से कम, आपको l1 * l2 * l3
उस गड़बड़ की गणना करने से पहले गणना करनी चाहिए ।
अंत में, आप बहुत से कॉल कर रहे हैं pow
, जो बेहद धीमा है। ध्यान दें कि उनमें से कई कॉल फॉर्म (l1 * l2 * l3) (1/3) के हैं । उनमें से कई कॉल pow
एकल कॉल के साथ की जा सकती हैं std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
इसके साथ,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
बन जाता है X * l123_pow_1_3
।
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
बन जाता है X / l123_pow_1_3
।
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
बन जाता है X * l123_pow_4_3
।
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
बन जाता है X / l123_pow_4_3
।
मैपल स्पष्ट याद किया।
उदाहरण के लिए, लिखने का एक बहुत आसान तरीका है
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
यह मानते हुए कि l1
, l2
और l3
जटिल संख्याओं के बजाय वास्तविक हैं, और यह कि वास्तविक घनमूल (सिद्धांत जटिल जड़ के बजाय) निकाले जाने हैं, उपरोक्त घटाता है
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
या
2.0/(3.0 * l123_pow_1_3)
के cbrt_l123
बजाय का उपयोग l123_pow_1_3
, प्रश्न में बुरा अभिव्यक्ति को कम कर देता है
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
हमेशा डबल चेक करें, लेकिन हमेशा की तरह सरल भी करें।
यहाँ ऊपर आने में मेरे कुछ कदम हैं:
// Step 0: Trim all whitespace.
T=(mu*(pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1+pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l2-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1+pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l3)/a+K*(l1*l2*l3-0.1e1)*l1*l2)*N3/l1/l2;
// Step 1:
// l1*l2*l3 -> l123
// 0.1e1 -> 1.0
// 0.4e1 -> 4.0
// 0.3e1 -> 3
l123 = l1 * l2 * l3;
T=(mu*(pow(l1*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l1-pow(l2*pow(l123,-1.0/3),a)*a/l1/3-pow(l3*pow(l123,-1.0/3),a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l2/3+pow(l2*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l2-pow(l3*pow(l123,-1.0/3),a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l3/3-pow(l2*pow(l123,-1.0/3),a)*a/l3/3+pow(l3*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 2:
// pow(l123,1.0/3) -> cbrt_l123
// l123*pow(l123,-4.0/3) -> pow(l123,-1.0/3)
// (pow(l123,-1.0/3)-pow(l123,-1.0/3)/3) -> 2.0/(3.0*cbrt_l123)
// *pow(l123,-1.0/3) -> /cbrt_l123
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T=(mu*(pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1-pow(l2/cbrt_l123,a)*a/l1/3-pow(l3/cbrt_l123,a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2-pow(l3/cbrt_l123,a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3-pow(l2/cbrt_l123,a)*a/l3/3+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 3:
// Whitespace is nice.
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)*a/l1/3
-pow(l3/cbrt_l123,a)*a/l1/3)/a
+K*(l123-1.0)*l2*l3)*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3
+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)*a/l2/3)/a
+K*(l123-1.0)*l1*l3)*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3
-pow(l2/cbrt_l123,a)*a/l3/3
+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a
+K*(l123-1.0)*l1*l2)*N3/l1/l2;
// Step 4:
// Eliminate the 'a' in (term1*a + term2*a + term3*a)/a
// Expand (mu_term + K_term)*something to mu_term*something + K_term*something
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+K*(l123-1.0)*l2*l3*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+K*(l123-1.0)*l1*l3*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l3))*N3/l1/l2
+K*(l123-1.0)*l1*l2*N3/l1/l2;
// Step 5:
// Rearrange
// Reduce l2*l3*N1/l2/l3 to N1 (and similar)
// Reduce 2.0/(3.0*cbrt_l123)*cbrt_l123/l1 to 2.0/3.0/l1 (and similar)
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3))*N3/l1/l2
+K*(l123-1.0)*N1
+K*(l123-1.0)*N2
+K*(l123-1.0)*N3;
// Step 6:
// Factor out mu and K*(l123-1.0)
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( ( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3)*N1/l2/l3
+ (-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3)*N2/l1/l3
+ (-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3)*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
// Step 7:
// Expand
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1*N1/l2/l3
-pow(l2/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l3/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l1/cbrt_l123,a)/l2/3*N2/l1/l3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2*N2/l1/l3
-pow(l3/cbrt_l123,a)/l2/3*N2/l1/l3
-pow(l1/cbrt_l123,a)/l3/3*N3/l1/l2
-pow(l2/cbrt_l123,a)/l3/3*N3/l1/l2
+pow(l3/cbrt_l123,a)*2.0/3.0/l3*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
// Step 8:
// Simplify.
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
गलत जवाब, जानबूझकर विनम्रता के लिए रखा गया
ध्यान दें कि यह त्रस्त है। यह गलत है।
अपडेट करें
मैपल स्पष्ट याद किया। उदाहरण के लिए, लिखने का एक बहुत आसान तरीका है
(pow (l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow (l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3.11
यह मानते हुए कि l1
, l2
और l3
जटिल संख्याओं के बजाय वास्तविक हैं, और यह कि असली घन जड़ (सिद्धांत जटिल जड़ के बजाय) निकाले जाने हैं, उपरोक्त शून्य को कम कर देता है। शून्य की यह गणना कई बार दोहराई जाती है।
दूसरा अपडेट
अगर मैंने गणित सही किया है ( कोई गारंटी नहीं है कि मैंने गणित सही किया है), प्रश्न में बुरा अभिव्यक्ति कम हो जाती है
l123 = l1 * l2 * l3;
cbrt_l123_inv = 1.0 / cbrt(l123);
nasty_expression =
K * (l123 - 1.0) * (N1 + N2 + N3)
- ( pow(l1 * cbrt_l123_inv, a) * (N2 + N3)
+ pow(l2 * cbrt_l123_inv, a) * (N1 + N3)
+ pow(l3 * cbrt_l123_inv, a) * (N1 + N2)) * mu / (3.0*l123);
उपरोक्त मानता है कि l1
, l2
और l3
सकारात्मक वास्तविक संख्याएँ हैं।
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
को एक चर के साथ बदलना है ... आपको अपने कोड को बेंचमार्क करने की आवश्यकता है यह सुनिश्चित करने के लिए कि यह तेज़ या धीमी गति से चलता है, हालांकि।