2011-10-27 18 views
8

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

एक उदाहरण के रूप में, LAPACK (फोरट्रान) है, जो अपने कार्य (सिंगल और डबल) में से प्रत्येक के दो संस्करण प्रदान करता है पर एक नज़र डालें। इसके अलावा सी गणित पुस्तकालय (उदाहरण, expf और एक्स)।

स्पष्ट करने के लिए, मैं निम्नलिखित (काल्पनिक) उदाहरण की तरह कुछ का समर्थन करना चाहते:

float MyFloatFunc(float x) { 
    return expf(-2.0f * x)*logf(2.75f*x); 
} 

double MyDoubleFunc(double x) { 
    return exp(-2.0 * x)*log(2.75*x); 
} 

मैं निम्नलिखित तरीकों के बारे में सोचा है: समारोह नाम के लिए

  1. मैक्रो का उपयोग करना ।

    #ifdef USE_FLOAT 
    #define MYFUNC MyFloatFunc 
    #else 
    #define MYFUNC MyDoubleFunc 
    #endif 
    
  2. चल बिन्दु प्रकार के लिए मैक्रो का उपयोग करना: यह अभी भी दो अलग-अलग स्रोत codebases की आवश्यकता है। यह मैं दो अलग अलग संस्करणों में codebase साझा करने के लिए अनुमति देता है:

    #ifdef USE_FLOAT 
    #define NUMBER float 
    #else 
    #define NUMBER double 
    #endif 
    
  3. बस दो अलग-अलग पुस्तकालयों के विकास, और सिर दर्द को बचाने की कोशिश के बारे में भूल जाते हैं।

क्या किसी के पास कोई सिफारिश या अतिरिक्त सुझाव हैं?

उत्तर

7

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

#ifdef USE_FLOAT 
#define C(x) x##f 
#else 
#define C(x) x 
#endif 

... C(2.0) ... C(sin) ... 
+0

हां, उस उत्कृष्ट बिंदु के लिए धन्यवाद। यहां लक्ष्य "डबल" के सटीक लाभ के खिलाफ "सिंगल" की निष्पादन गति को व्यापार करना बंद करना है। –

2

आप के लिए बड़ा सवाल होगा::

  • यह है

    फिर भी, अगर आप एक codebase का तरीका अपनाते हैं, निम्नलिखित स्थिरांक और मानक पुस्तकालय कार्यों के लिए काम करना चाहिए दो अलग unobfuscated स्रोत पेड़, या एक obfuscated एक बनाए रखने के लिए आसान है?

आप प्रस्तावित प्रचलित कोडिंग है, तो आप किसी भी असज्जित स्थिरांक या गैर मैक्रो फ़ंक्शन कॉल (या समारोह निकायों) लिखने के लिए नहीं बहुत सावधान किया जा रहा है, एक असार फैशन में कोड लिखने के लिए होगा।

यदि आपके पास अलग-अलग स्रोत कोड पेड़ हैं, तो यह सुनिश्चित करने के लिए कोड सरल होगा कि प्रत्येक पेड़ सामान्य (गैर-obfuscated) सी कोड जैसा दिखाई देगा, लेकिन अगर 'फ्लोट' संस्करण में YourFunctionA में कोई बग है, क्या आप हमेशा 'डबल' संस्करण में मिलान करने के लिए याद रखना याद रखेंगे।

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

मैं शायद एक भी कोड बेस और दीवार से दीवार मैक्रो के साथ जाना चाहते हैं। लेकिन मुझे यकीन नहीं है कि यह सबसे अच्छा है, और दूसरी तरफ इसके फायदे भी हैं।

5

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

mylib.h:

#ifndef MYLIB_H_GUARD 
    #ifdef MYLIB_H_PASS2 
    #define MYLIB_H_GUARD 1 
    #undef C 
    #undef FLT 
    #define C(X) X 
    #define FLT double 
    #else 
    /* any #include's needed in the header go here */ 

    #undef C 
    #undef FLT 
    #define C(X) X##f 
    #define FLT float 
    #endif 

    /* All the dual-version stuff goes here */ 
    FLT C(MyFunc)(FLT x); 

    #ifndef MYLIB_H_PASS2 
    /* prepare 2nd pass (for 'double' version) */ 
    #define MYLIB_H_PASS2 1 
    #include "mylib.h" 
    #endif 
#endif /* guard */ 

mylib.c:

#ifdef MYLIB_C_PASS2 
    #undef C 
    #undef FLT 
    #define C(X) X 
    #define FLT double 
#else 
    #include "mylib.h" 
    /* other #include's */ 

    #undef C 
    #undef FLT 
    #define C(X) X##f 
    #define FLT float 
#endif 

/* All the dual-version stuff goes here */ 
FLT C(MyFunc)(FLT x) 
{ 
    return C(exp)(C(-2.0) * x) * C(log)(C(2.75) * x); 
} 

#ifndef MYLIB_C_PASS2 
    /* prepare 2nd pass (for 'double' version) */ 
    #define MYLIB_C_PASS2 1 
    #include "mylib.c" 
#endif 

प्रत्येक फ़ाइल #include रों ही एक अतिरिक्त समय, दूसरी पास पर अलग मैक्रो परिभाषाओं का उपयोग, के दो संस्करणों उत्पन्न करने के लिए मैक्रोज़ का उपयोग करने वाला कोड।

कुछ लोग इस दृष्टिकोण पर ऑब्जेक्ट कर सकते हैं, हालांकि।

+0

मैं कार्यान्वयन के लिए इस दृष्टिकोण का उपयोग कर सकता हूं। मैं कभी भी हेडर के लिए इसका उपयोग नहीं करता। जब लोग सिर्फ लाइब्रेरी का उपयोग करना चाहते हैं तो लोगों को इस प्रकार के कार्यान्वयन विवरण को देखने की आवश्यकता नहीं है। मैं सभी मैक्रो परिभाषाओं को एक फ़ाइल में भी स्थानांतरित कर दूंगा। –

+0

बहुत डरावना - और बहुत रोचक। कभी नहीं पता था कि एक हेडर फ़ाइल # शामिल हो सकती है। मुझे आश्चर्य है कि क्या यह चाल सी प्रीप्रोसेसर ट्यूरिंग-पूर्ण बनाता है (सी ++ टेम्पलेट्स की तरह)? –

1

<tgmath.h> हैडर, सी 1999 में मानकीकृत, दिनचर्या के प्रकार सामान्य कॉल प्रदान करता है में <math.h> और <complex.h>। <tgmath.h> शामिल करने के बाद, स्रोत टेक्स्ट "पाप (एक्स)" पापल को कॉल करेगा यदि एक्स लंबे समय तक डबल है, तो x डबल होने पर पाप, और यदि x फ़्लोट हो तो sinf।

आप अब भी अपने स्थिरांक conditionalize ताकि आप के रूप में उपयुक्त "3.1" या "3.1f" का उपयोग की आवश्यकता होगी। इसके लिए आपकी कई आवश्यकताओं के आधार पर सिंटैक्टिक तकनीकें हैं और आपके लिए अधिक सौंदर्यप्रद दिखाई देता है। स्थिरता के लिए जो वास्तव में फ्लोट परिशुद्धता में दर्शाए जाते हैं, आप बस फ्लोट फॉर्म का उपयोग कर सकते हैं। उदा।, "Y = .5f * x" स्वचालित रूप से .5f से .5 में परिवर्तित हो जाएगा यदि x डबल है। हालांकि, "पाप (.5 एफ)" sinf (.5f) का उत्पादन करेगा, जो पाप (.5) से कम सटीक है।

आप किसी एक स्पष्ट परिभाषा को conditionalization कम करने में सक्षम हो सकता है:

#if defined USE_FLOAT 
    typedef float Float; 
#else 
    typedef double Float; 
#endif 

तो फिर तुम इस तरह मायनों में स्थिरांक का उपयोग कर सकते हैं:

const Float pi = 3.14159265358979323846233; 
Float y = sin(pi*x); 
Float z = (Float) 2.71828182844 * x; 

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

+0

सूचक के लिए धन्यवाद tgmath.h। मुझे यह जानकर खुशी हो रही है कि यह अस्तित्व में है, लेकिन किस प्रकार की फ़ंक्शन को चुनने के लिए प्रकार की जानकारी का उपयोग करना है? यह बात सी 99 में कैसे आई? –

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