2017-01-24 18 views
8

मैं कुछ जावा मैथ फ़ंक्शन मूल सी स्रोत कोड के माध्यम से खुदाई कर रहा था। विशेष रूप से tanh(), क्योंकि मैं यह देखने के लिए उत्सुक था कि उन्होंने इसे कैसे कार्यान्वित किया। हालांकि, what I found मुझे हैरान कर दिया:जावा/सी: ओपनजेडीके देशी तन्ह() कार्यान्वयन गलत है?

double tanh(double x) { 
    ... 
    if (ix < 0x40360000) {   /* |x|<22 */ 
     if (ix<0x3c800000)   /* |x|<2**-55 */ 
      return x*(one+x);  /* tanh(small) = small */ 
    ... 
} 

टिप्पणी, taylor series of tanh(x) around 0 इंगित करता है, के साथ शुरू होता है:

tanh(x) = x - x^3/3 + ... 

फिर क्यों यह दिखता है जैसे वे के रूप में इसे लागू किया:

tanh(x) = x * (1 + x) 
     = x + x^2 

जो स्पष्ट रूप से सही विस्तार नहीं है, और tanh(x) = x का उपयोग करने से भी बदतर अनुमान है (जो होगा तेज), के रूप में इस साजिश ने संकेत दिया:

enter image description here

(बोल्ड लाइन एक शीर्ष पर संकेत दिया है। अन्य ग्रे एक log(abs(x(1+x) - tanh(x))) है। सिग्मोइड निश्चित रूप से tanh(x) है।)

तो, क्या यह कार्यान्वयन में एक बग है, या यह कुछ समस्या ठीक करने के लिए हैक है (जैसे संख्यात्मक मुद्दों, जिन्हें मैं वास्तव में नहीं सोच सकता)? ध्यान दें कि मुझे उम्मीद है कि दोनों दृष्टिकोणों का नतीजा बिल्कुल वैसा ही होगा जैसा कि वास्तव में 1 + x को जोड़ने के लिए पर्याप्त mantisse बिट्स नहीं हैं, x < 2^(- 55) के लिए।

संपादित: I will include a link to the version of the code at the time of writing, for future reference, as this might get fixed.

+1

यह इस प्रकार का बकवास है जो रॉकेट को विस्फोट का कारण बनता है। –

+1

पूरी तरह से 'tanh()' _odd_ फ़ंक्शन होने की अपेक्षा करता है, इसलिए 'y = f (x) -> y = -f (-x)'। 'x + x^2' टूटता है। केवल एक ही विचार है कि 'f (-0.0)' पर एक + चिह्न को मजबूर करना है, लेकिन यह 'tanh (x) = x + 0.0; 'के साथ करना आसान है। आईएमओ, एक त्रुटि जो खुद को 'x | <2 ** - 55' ... या गोलाकार झंडे के साथ कुछ नहीं दिखा सकती है। – chux

+0

लक्ष्य प्लेटफ़ॉर्म पर 'x * (एक + x)' x + 0.0' को प्रभावित करने का एक मुश्किल तरीका हो सकता है? – chux

उत्तर

6

की स्थिति है, जिसमें कि कोड के निष्पादित होने के अंतर्गत, और मान कि आईईईई-754 डबल परिशुद्धता फ्लोटिंग बिंदु निरूपण और गणित उपयोग में हैं, 1.0 + x हमेशा 1.0 करने का मूल्यांकन करेंगे, तो x * (1.0 + x) हमेशा x का मूल्यांकन करेगा। केवल x लौटने की बजाए गणना के प्रदर्शन के निष्पादन योग्य प्रभाव को केवल बाहरी (कार्य करने के लिए) आईईईई "अयोग्य" स्थिति ध्वज सेट करना होगा।

हालांकि मुझे जावा से एफपी स्थिति झंडे से पूछताछ करने का कोई तरीका नहीं है, अन्य मूल कोड उन्हें समझदारी से पूछ सकता है। अधिक नहीं की तुलना में होने की संभावना है, हालांकि, कार्यान्वयन के लिए व्यावहारिक कारण से इन टिप्पणियों से the Javadocs for java.StrictMath में दी गई है:

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

जावा गणित पुस्तकालय को fdlibm संस्करण 5.3 के संबंध में परिभाषित किया गया है। जहां fdlibm फ़ंक्शन (जैसे एकोस) के लिए एक से अधिक परिभाषा प्रदान करता है, "आईईईई 754 कोर फ़ंक्शन" संस्करण का उपयोग करें (फ़ाइल में रहना जिसका नाम अक्षर ई से शुरू होता है)।तरीकों जो fdlibm अर्थ विज्ञान की आवश्यकता होती है sin, cos, tan, asin, acos, atan, exp, log, log10, cbrt, atan2, pow, sinh, cosh, tanh, hypot, expm1, और log1p हैं।

(जोर जोड़ा गया।) आप सी स्रोत कोड में #include "fdlibm.h" में नोट करेंगे जो इसे जावाडोक टिप्पणियों से जोड़ता है।

+1

ध्यान दें कि सीमा | x | <2 ** (- 55) में असामान्य (असामान्य) ऑपरेंड शामिल हैं, और इसलिए यह कोड अचूक ध्वज के अलावा, असामान्य और अंडरफ्लो झंडे भी बढ़ा सकता है। कारण यह है कि कोई भी 'x * 1.0' का उपयोग नहीं कर सकता है क्योंकि आईएसई -754 आईएसओ सी के लिए बाइंडिंग के तहत, इसे केवल' x' (आईएसओ सी 99 के सेक्शन एफ.8.2) के लिए अनुकूलित किया जा सकता है, और इस तरह के असाइनमेंट में कोई फ़्लोटिंग नहीं होगी -पॉइंट झंडे। – njuffa

+0

@njuffa मैंने सोचा था कि अंडरफ्लो ध्वज केवल तभी उठाया गया था जब ऑपरेशन का परिणाम छोटा होने के अलावा अचूक था, ताकि यह ध्वज कभी भी '1.0 * x' तक नहीं उठाया जा सके? –

+0

@PascalCuoq अच्छा बिंदु, आप सही हो सकते हैं। यदि ऐसा है, तो 'x * 1.0' कंप्यूटर्स को अनुकूलित करने के लिए उपयुक्त नहीं हो सकता है। मुझे अंडरफ्लो फ्लैग को बढ़ाने के सभी विवरण याद नहीं हैं (वह सबसे जटिल है), लेकिन मुझे याद है कि आईईईई 754-19 85 (जो एफडीआईएलबीएम कोड से प्रासंगिक है) ने योगदान कारकों के लिए वैकल्पिक डिजाइन की अनुमति दी "टिननेस" और "सटीकता का नुकसान", जहां पूर्व को गोल करने से पहले या बाद में पता लगाया जा सकता था, और बाद में अनिवार्य रूप से अयोग्यता शामिल नहीं थी। – njuffa

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