2010-07-08 35 views
27

मैं आज researchers discovering that NVidia's Phys-X libraries use x87 FP vs. SSE2 पढ़ रहा था। स्पष्ट रूप से यह समांतर डेटासेट के लिए उप-शीर्ष होगा जहां गति सटीकता को टंप करता है। हालांकि, लेख लेखक उद्धृत करने के लिए पर चला जाता है:विस्तारित (80-बिट) x87 में डबल फ्लोटिंग पॉइंट, एसएसई 2 नहीं - हम इसे याद नहीं करते हैं?

इंटेल देर 2000 में पी 4 की शुरूआत के साथ x87 के उपयोग को हतोत्साहित एएमडी 2003 में K8 के बाद से x87 पदावनत, x86-64 के रूप में शुरू SSE2 के साथ परिभाषित किया गया है समर्थन; वीआईए के सी 7 ने 2005 से एसएसई 2 का समर्थन किया है। विंडोज़ के 64-बिट संस्करणों में, x87 को उपयोगकर्ता-मोड के लिए बहिष्कृत किया गया है, और पूरी तरह से कर्नेल-मोड में प्रतिबंधित है। उद्योग में काफी हर किसी को 2005 के बाद से x87 अधिक SSE की सिफारिश की है और जब तक सॉफ्टवेयर एक एम्बेडेड पेंटियम पर चलाने के लिए या 486.

मैं इस बारे में सोचा है वहाँ, कोई कारणों x87 उपयोग करने के लिए कर रहे हैं। मुझे पता है कि x87 मूल्यों की गणना करने के लिए आंतरिक रूप से 80-बिट विस्तारित युगल का उपयोग करता है, और एसएसई 2 नहीं करता है। क्या इससे कोई फर्क नहीं पड़ता? यह मेरे लिए आश्चर्यजनक लगता है। मुझे पता है कि जब मैं विमान में बिंदुओं, रेखाओं और बहुभुजों पर गणना करता हूं, तो घटाव करते समय मूल्य आश्चर्यजनक रूप से गलत हो सकते हैं, और परिशुद्धता की कमी के कारण क्षेत्र गिर सकते हैं और एक-दूसरे को लाइन कर सकते हैं। 80-बिट मान बनाम 64-बिट मानों का उपयोग करने में मदद मिल सकती है, मैं कल्पना करूंगा।

क्या यह गलत है? यदि नहीं, तो x87 चरणबद्ध होने पर विस्तारित डबल एफपी संचालन करने के लिए हम क्या उपयोग कर सकते हैं?

+1

वास्तव में आपके प्रश्न का उत्तर नहीं है, लेकिन व्यक्तिगत रूप से मैं 128-बिट आईईईई 754 बाइनरी प्रारूप मुख्यधारा बनने की उम्मीद कर रहा हूं। –

+0

@ मार्क - गंभीरता से, बस इतना समय क्या ले रहा है? इससे पहले कि AVX एक मानक हो सकता है ... – codekaizen

+1

[यह] (https://www.cs.uaf.edu/2012/fall/cs301/lecture/11_02_other_float.html) कारण क्या था इसका एक अच्छा जवाब है x87 को हतोत्साहित करने के लिए। और हां, एसएसई की गणना कम सटीक है, यह आधुनिक जेआईटी-कंपाइलर्स (पारंपरिक x87- आधारित कंपाइलर्स की तुलना में) पर स्पष्ट रूप से देखी जाती है। –

उत्तर

21

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

दूसरी समस्या, जो केवल किसी व्यक्ति को असेंबली लिखने (या अप्रत्यक्ष रूप से लिखित असेंबली, किसी कंपाइलर के लिए कोड जेनरेटर लिखने के मामले में) के दृष्टिकोण से संबंधित है, यह है कि x87 एक रजिस्टर स्टैक का उपयोग करता है, जबकि एसएसई व्यक्तिगत रूप से सुलभ रजिस्टरों का उपयोग करता है। X87 के साथ आपके पास स्टैक में हेरफेर करने के लिए अतिरिक्त निर्देशों का एक समूह है, और मुझे लगता है कि इंटेल और एएमडी उन अतिरिक्त स्टैक-मैनिपुलेशन x87 निर्देशों को तेजी से चलाने की कोशिश करने के बजाय एसएसई कोड के साथ अपने प्रोसेसर को तेजी से चलाएंगे।

बीटीडब्ल्यू अगर आपको गलतता के साथ समस्याएं आ रही हैं, तो आप लेख "What every programmer should know about floating-point arithmetic" पर एक नज़र डालना चाहते हैं, और फिर इसके बजाय एक मनमाने ढंग से सटीक गणित पुस्तकालय (उदाहरण के लिए जीएमपी) का उपयोग करना चाहेंगे।

+6

कंप्यूटर्स को अनुकूलित करना काफी खराब है, लेकिन एक जेआईटी को आजमाएं जिसमें छोटी विधियों को रेखांकित करने की क्षमता है (और इसलिए इन-मेमोरी टेम्पस की संख्या अलग-अलग होती है)। कभी-कभी मैं इस विधि को कॉल करता हूं और एक उत्तर प्राप्त करता हूं, कभी-कभी मैं एक ही विधि को उसी तर्क के साथ कॉल करता हूं और एक अलग परिणाम प्राप्त करता हूं, इस पर निर्भर करता है कि जिटर ने कॉल को रेखांकित किया है या नहीं! यह ट्रैक करने के लिए एक मजेदार प्रतिगमन था। –

+0

हां, मैं देखता हूं, यह इस प्रकार के विकल्पों को बनाने वाले कंपाइलर्स के साथ जटिल हो जाता है, जब जेआईटी कंपाइलर्स इसे करते हैं तो मोर्सो। परिशुद्धता के रूप में, मैं वर्तमान में संख्या को 0. 0..1] स्केल करता हूं और बिट्स को रद्द करने के कारण शोर को कम करने के लिए सामान्य बिट्स को हटा देता हूं, और केवल कल्पना की जाती है कि 80 बिट्स मुझे और अधिक कमरा देगी। जबकि सच है, स्पष्ट रूप से, साइड इफेक्ट्स लागत से बहुत अधिक हैं। मैं इसे क्यूपी हार्डवेयर पर परीक्षण करने की उम्मीद करता हूं ... जब भी यह दिखाता है। – codekaizen

+0

@ जो व्हाइट यदि आप जावा का उपयोग कर रहे हैं और आपको हर बार फ्लोटिंग पॉइंट गणित करने के लिए एक ही परिणाम की आवश्यकता होती है, तो 'सख्त एफपी' कीवर्ड के उपयोग की जांच करें। यह गणित को आईईईई 754 होने के लिए मजबूर करता है और मूल प्लेटफार्म जो भी करता है (उदाहरण के लिए 32 बी इंटेल पर x87)। http://en.wikipedia.org/wiki/Strictfp – KitsuneYMG

2

दूसरा उत्तर यह सुझाव देता है कि 80-बिट परिशुद्धता का उपयोग करना एक बुरा विचार है, लेकिन ऐसा नहीं है। यह खाड़ी पर अपर्याप्तता रखने में कभी-कभी महत्वपूर्ण भूमिका निभाता है, उदाहरण के लिए देखें डब्ल्यू कहान के लेखन।

यदि आप इसे गति से दूर कर सकते हैं तो हमेशा 80-बिट इंटरमीडिएट अंकगणित का उपयोग करें। यदि इसका मतलब है कि आपको x87 गणित का उपयोग करना है, तो ऐसा करें। इसके लिए समर्थन सर्वव्यापी है और जब तक लोग सही काम करते रहते हैं, यह सर्वव्यापी रहेगा।

+3

हालांकि, कुछ हद तक विडंबना यह है कि 80-बिट x87 रजिस्टरों के उपयोग से मध्यवर्ती 64-बिट परिशुद्धता (* नहीं * 80-बिट परिशुद्धता) नियमित 53-बिट युगल पर सरल अंकगणितीय परिचालनों के लिए * कम * सटीक परिणाम ले सकती है। सामान्य राउंड-टू-टू-राउंडिंग मोड को मानते हुए, आईईईई 754 बाइनरी 64 मानों पर ऑपरेशन '1e16 + 2.9999' एसएसई 2 का उपयोग कर मशीन पर '10000000000000002.0' का सही ढंग से गोल परिणाम देता है, लेकिन' 10000000000000004.0 का ग़लत रूप से गोल परिणाम 'जब एफपीयू परिशुद्धता के साथ x87 का उपयोग 64-बिट परिशुद्धता के डिफ़ॉल्ट से नहीं बदला जाता है, तो डबल राउंडिंग के लिए धन्यवाद। –

+2

ऐसे कुछ मामले हैं जहां x + y की गणना करने के लिए डबल-परिशुद्धता का उपयोग करके 1/2ulp की राउंड-ऑफ़ त्रुटि के साथ परिणाम मिलेगा, जबकि विस्तारित-परिशुद्धता का उपयोग करते हुए और डबल में कनवर्ट करने से 2049/4096ulp की राउंड-ऑफ़ त्रुटि उत्पन्न होगी । दूसरी तरफ, ऐसे कई मामले हैं जहां एक्स + वाई + जेड की गणना करने के लिए विस्तारित परिशुद्धता का उपयोग करना एक सटीक परिणाम देगा, जबकि "डबल" का उपयोग करने से परिणाम मिलेगा जो * दूर * कम सटीक है, या कुछ मामलों में बस सादा गलत – supercat

5

विस्तारित-परिशुद्धता गणित का उचित उपयोग करने के लिए, यह आवश्यक है कि एक भाषा एक प्रकार का समर्थन करे जिसका उपयोग इंटरमीडिएट कंप्यूटेशंस के परिणाम को संग्रहीत करने के लिए किया जा सके, और उन परिणामों को उत्पन्न करने वाले अभिव्यक्तियों के लिए प्रतिस्थापित किया जा सके।इस प्रकार, दिया:

void print_dist_squared(double x1, double y1, double x2, double y2) 
{ 
    printf("%12.6f", (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); 
} 

वहाँ कुछ प्रकार है कि के रूप में लिखा जा करने के लिए कब्जा और आम उप भाव x2-x1 और y2-y1 को बदलने के लिए, कोड की इजाजत दी इस्तेमाल किया जा सकता होना चाहिए: बदले बिना

void print_dist_squared(double x1, double y1, double x2, double y2) 
{ 
    some_type dx = x2-x1; 
    some_type dy = y2-y1; 
    printf("%12.6f", dx*dx + dy*dy); 
} 

कार्यक्रम के अर्थशास्त्र। दुर्भाग्यवश, एएनएसआई सी किसी भी प्रकार को निर्दिष्ट करने में असफल रहा जिसका उपयोग some_type के लिए प्लेटफ़ॉर्म पर किया जा सकता है जो विस्तारित-परिशुद्धता गणना करता है, और एएनएसआई के बॉट किए गए समर्थन को दोष देने के बजाय विस्तारित-सटीक प्रकारों के अस्तित्व के लिए इंटेल को दोष देना कहीं अधिक आम हो गया।

वास्तव में, विस्तारित परिशुद्धता प्रकार फ्लोटिंग प्वाइंट इकाइयों के बिना प्लेटफार्मों पर बस के रूप में ज्यादा मूल्य के रूप में वे x87 प्रोसेसर पर करते हैं, इस तरह के प्रोसेसर पर के बाद से एक गणना की तरह x + y + z निम्न चरणों का पालन करना पड़ेगा:

  1. अनपैक अपूर्णांश, प्रतिपादक, और संभवतः अलग रजिस्टरों में एक्स के हस्ताक्षर (प्रतिपादक और प्रवेश कर सकते हैं अक्सर "डबल चारपाई")
  2. अनपैक y वैसे ही।
  3. निचले एक्सपोनेंट के साथ मान के मंटिसा को सही स्थानांतरित करें, यदि कोई है, और फिर मान जोड़ें या घटाएं।
  4. यदि एक्स और वाई के अलग-अलग संकेत थे, तो बाएं-बिट को मंटिसा छोड़ दें जब तक कि बाएंतम बिट 1 न हो और एक्सपोनेंट को उचित रूप से समायोजित करें।
  5. एक्सपोनेंट और मंटिसा को डबल प्रारूप में वापस पैक करें।
  6. उस अस्थायी परिणाम को अनपैक करें।
  7. अनपैक जेड।
  8. निचले एक्सपोनेंट के साथ मान के मंटिसा को सही स्थानांतरित करें, यदि कोई है, और फिर मान जोड़ें या घटाएं।
  9. यदि पहले के परिणाम और जेड के अलग-अलग संकेत थे, तो बाएं-बिट को मंटिसा छोड़ दें जब तक कि बाएंतम बिट 1 न हो और एक्सपोनेंट को उचित रूप से समायोजित करें।
  10. एक्सपोनेंट और मंटिसा को डबल प्रारूप में वापस पैक करें।

विस्तारित-सटीक प्रकार का उपयोग करने से चरण 4, 5, और 6 को समाप्त करने की अनुमति मिल जाएगी। चूंकि 53-बिट मंटिसा चार 16-बिट रजिस्ट्रार या दो 32-बिट रजिस्टरों से कम फिट होने के लिए बहुत बड़ा है, इसलिए 64-बिट मंटिसा के साथ एक प्रदर्शन करने से 53-बिट मंटिसा का उपयोग करने से धीमा नहीं होता है, इसलिए विस्तारित-परिशुद्धता गणित एक ऐसी भाषा में के बिना तेजी से गणना प्रदान करता है जो अस्थायी परिणाम रखने के लिए उचित प्रकार का समर्थन करता है। इंटेल को एफपीयू प्रदान करने के लिए इंटेल को गलती करने का कोई कारण नहीं है जो गैर-एफपीयू चिप्स पर सबसे प्रभावी विधि फैशन में फ्लोटिंग-पॉइंट गणित कर सकता है।

+1

ठीक है, लेकिन मुझे लगता है कि हम * इंटेल को गलती कर सकते हैं, मानकों के अनुरूप तरीके से सही ढंग से गोल अंकगणित मूल अंकगणितीय परिचालन (64-बिट युगल पर) * * पर *। हां, आप 64 बिट्स के बजाय एफपीयू परिशुद्धता को 53 बिट्स में बदल सकते हैं, लेकिन यह 64-बिट परिशुद्धता की अपेक्षा रखने वाले लाइब्रेरी कोड के साथ हस्तक्षेप करने वाले जोखिमपूर्ण, धीमी, जोखिम है, और समस्या को हल भी नहीं करता है: जबकि यह डबल राउंडिंग को समाप्त करता है सामान्य डोमेन, यह एक्सपोनेंट रेंज को नहीं बदलता है, इसलिए अभी भी अंडरफ्लो पर डबल राउंडिंग की संभावना छोड़ देता है। एसएसई (2) इस संबंध में एक बड़ा सुधार है। –

+0

@ मार्क डिकिंसन: हालांकि विशेष अनुप्रयोग हैं जिनके लिए छोटे प्रकार के संचालन के साथ थोड़ा-लगातार फ़्लोटिंग-पॉइंट व्यवहार की आवश्यकता होती है, अधिकांश अनुप्रयोगों के लिए विस्तारित परिशुद्धता के लिए उचित समर्थन होना बेहतर होता है। मैं एसएसई (2) और x87 को विभिन्न प्रयोजनों की सेवा के रूप में देखता हूं, और ऐसा लगता है कि भाषाएं उन्हें उत्सुकता से बढ़ावा देने और सख्त फ़्लोटिंग-पॉइंट प्रकार दोनों का समर्थन करती हैं; इसके अलावा, सख्त प्रकारों से जुड़े अभिव्यक्तियों को आईएमएचओ को "स्पष्ट रूप से" अपने स्वयं के प्रकार के लिए मजबूर करने के बाद बड़े प्रकार के रूप में परिवर्तनीय होना चाहिए, इसलिए यदि एफ 1 और एफ 2 सख्त फ्लोट प्रकार थे, 'डी 1 = एफ 1 * एफ 2' ... – supercat

+0

... होगा 'डी 1 = (फ्लोट) (एफ 1 * एफ 2) के रूप में लिखा जाना चाहिए;' [नहीं 'डी 1 = (डबल) (एफ 1 * एफ 2); '!]। मुझे लगता है कि ऐसे मामलों में जहां कोई व्यक्ति 'डी 1 = एफ 1 * एफ 2 लिखता है;' वहां बहुत अधिक संभावना है कि (1) कोड या तो 'd1 = (double) f1 * f2;', (2) कहने का इरादा रखता है) एक प्रोग्रामर जो कोड को देखता है, इसका मतलब है कि, या (3) एक प्रोग्रामर जो कोड को देखता है, सोचता है कि इसका मतलब यह था कि इसका मतलब था। कोड को 'डी 1 = (फ्लोट) (एफ 1 * एफ 2) के रूप में लिखा जाना आवश्यक है;' उन मामलों में जहां व्यवहार का उद्देश्य उन खतरों को खत्म कर देगा। – supercat

0

कई एप (ज्यादातर गेम) के लिए डबल परिशुद्धता एफ 80 (लगभग 2.5 निबल्स/अंक) से 11 बिट कम है, इससे चोट नहीं पहुंचीगी। लेकिन आपको कहने के लिए उपलब्ध सभी सटीकता की आवश्यकता होगी, अंतरिक्ष कार्यक्रम या चिकित्सा ऐप।

कुछ लोग भ्रामक हैं जब कुछ कहते हैं कि f80 (और इसके द्वारा निराश) स्टैक पर चल रहा है। एफपीयू रजिस्टर और स्टैक ऑपरेशन के समान संचालन, शायद इससे लोगों को भ्रमित कर दिया जाता है। यह वास्तव में मेमोरी आधारित (लोड/स्टोर) है, उदाहरण के लिए, सीडीईसीएल स्टडीकॉल जैसे सम्मेलन को कॉल करने के लिए, जो वास्तव में ढेर के माध्यम से पैरामीटर गुजरता है, की तुलना में प्रति-स्टैक नहीं है। और उसके साथ कुछ भी गलत नहीं है।

एसएसई का बड़ा लाभ वास्तव में कई भिन्न संचालन के साथ ऑपरेशन, 2, 4, 8 मानों को क्रमशः क्रमबद्ध करता है।हां आप सीधे पंजीकरण में स्थानांतरित कर सकते हैं, लेकिन आप अंत में वैसे भी स्मृति को स्मृति में स्थानांतरित कर देंगे।

एफ 80 का बड़ा नुकसान है, इसकी विषम 10 बाइट लंबी है, यह संरेखण को बाधित करती है। आपको तेजी से पहुंच के लिए 16 को संरेखित करना होगा। लेकिन सरणी के लिए वास्तव में व्यावहारिक नहीं है।

आपको अभी भी त्रिकोणमितीय और अन्य ट्रांस्डेंटल गणित परिचालनों के लिए fpu का उपयोग करना होगा। एएसएम के लिए, कई f80 चालें हैं जो वास्तव में मजेदार और उपयोगी हैं।

खेलों और नियमित सरल ऐप (लगभग सभी) के लिए, आप किसी की मृत्यु के बिना केवल दो बार उपयोग कर सकते हैं। लेकिन कुछ गंभीर, गणित या वैज्ञानिक ऐप के लिए आप केवल f80 को नहीं हटा सकते हैं।

+1

' धारावाहिक ऑपरेशन' का मतलब है। आपका मतलब है " समांतर ऑपरेशन "या सिम ऑपरेशन –

+2

'आपको अभी भी त्रिकोणमितीय और अन्य ट्रांस्डेंटल गणित परिचालनों के लिए fpu का उपयोग करना होगा।' यदि आपका मतलब x87 FSIN है, [FYL2X] (http://www.felixcloutier.com/x86/FYL2X।एचटीएमएल) (लॉग 2), आदि तो नहीं, यह गलत है। गणित पुस्तकालय एसएसई गणित के साथ सॉफ्टवेयर में उन कार्यों को लागू करते हैं। –

+1

x87 अप्रचलित होने से पहले, अच्छी गणित पुस्तकालयों ने एफएसआईएन का उपयोग नहीं किया, क्योंकि रेंज में कमी के लिए उपयोग किए जाने वाले पीई का आंतरिक मूल्य पर्याप्त सटीक नहीं है; केवल 66 बिट्स। इंटेल पीछे की तुलनात्मक कारणों के लिए इसे बदलने में सक्षम नहीं है, लेकिन [एफएसआईएन के पास +/- pi/2 के पास बड़ी त्रुटियां हैं) (https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error -बाउंड-बाय-1-3-क्विंटिलियन /) –