2014-05-03 28 views
8

जी ++ में, विभिन्न अंतर्निहित गणित कार्य कुछ स्थितियों के तहत constexpr हैं। उदाहरण के लिए, निम्नलिखित संकलन:__builtin_round एक निरंतर अभिव्यक्ति नहीं है

static constexpr double A = __builtin_sqrt(16.0); 
static constexpr double B = __builtin_pow(A, 2.0); 

हालांकि वे हमेशा कॉन्स्टेक्स नहीं होते हैं, यह तर्क पर निर्भर करता है। उदाहरण के लिए, निरंतर अभिव्यक्ति के रूप में उपयोग किए जाने पर __builtin_sqrt(NAN) संकलन त्रुटि में परिणाम देता है।

लेकिन मैं मुझे लगता है, जहां कि यह constexpr होना चाहिए एक अजीब मामला मार कर रहा हूँ, लेकिन यह नहीं है:

static constexpr double value() { return 1.23; } 
static constexpr double result = __builtin_round(__builtin_sqrt(value())); 

यह पैदा करता है:

a.cpp:2:73: error: ‘__builtin_round(1.1090536506409416e+0)’ is not a constant expression 
static constexpr double result = __builtin_round(__builtin_sqrt(value())); 
                     ^

मैं रूपों की कोशिश की है उपरोक्त कोड के, और मैंने पाया है कि:

  • __builtin_round समस्या में कुछ विशेष भूमिका है। इसे sqrt या pow जैसे कुछ अन्य अंतर्निहित गणित फ़ंक्शन के साथ प्रतिस्थापित करना त्रुटि को हल करता है। तो ऐसा लगता है कि __builtin_round में केवल कॉन्सएक्स समर्थन की कमी है। लेकिन ...
  • यदि value() को एक शाब्दिक 1.23 द्वारा प्रतिस्थापित किया गया है, तो यह भी त्रुटि को हटा देता है।
  • __builtin_sqrt को हटाकर, केवल __builtin_round(value()) छोड़कर, त्रुटि को भी हटा देता है।

मुझे यह जानना है कि round इस तरह से व्यवहार क्यों कर रहा है, और यदि कोई कामकाज है।

नोट। मुझे पता है कि बिल्टिन गणित कार्य, उनके कॉन्स्टेक्स-नेस के साथ, एक गैर-मानक कंपाइलर-विशिष्ट सुविधा हैं। कृपया मुझे व्याख्यान न करें कि मुझे इसका उपयोग क्यों नहीं करना चाहिए, या मुझे संकलन समय गणित करने की कोशिश क्यों नहीं करनी चाहिए। मेरे मामले में, कॉन्स्टेक्स गणित होना एक महत्वपूर्ण विशेषता है, और मैं G ++ के आधार पर ठीक हूं।

+0

गोल नहीं चल रहा है वर्तमान फ्लोटिंग पॉइंट राउंडिंग विधि पर निर्भर करता है, जिसे केवल रन टाइम पर जाना जाता है? –

+0

@AlanStokes मैंने भी इतना सिखाया, लेकिन जीसीसी मानता है कि गोलाकार मोड संकलन समय पर किसी भी तरह से जाना जाता है। जीसीसी में '-फनो-राउंडिंग-गणित' विकल्प देखें। इसके अलावा, अगर यह उस कारण था, कम से कम सिद्धांत में बहुत सारे एफपी ऑपरेटर कंस्ट्रैक्स नहीं होंगे (जो कम से कम जी ++ में हैं, जो अधिकांश गणित कार्यों के समान हैं)। –

उत्तर

3

मुझे एक और कामकाज का विचार है।

है: एक सहायक समारोह pass_through

template<typename T> 
constexpr T&& pass_through (T&& t) { return static_cast<T&&>(t); } 

का उपयोग इस तरह इसका इस्तेमाल:

static constexpr double value() { return 1.23; } 
static constexpr double result = __builtin_round(pass_through(__builtin_sqrt(value()))); 

इस कोड जी ++ में त्रुटि के बिना संकलित किया गया है।

मैं यह भी मानता हूं कि इस मुद्दे को जीसीसी को सूचित किया जाना चाहिए।

2

मैं केवल आपके प्रश्न का उत्तर दे सकता हूं, जो कि कोई कामकाज है या नहीं।

वहाँ है: एक सहायक constexpr चर का उपयोग करें।

हालांकि __builtin_round(__builtin_sqrt(value())) निरंतर अभिव्यक्ति के रूप में अस्वीकार कर दिया गया है, helper = value() स्वीकार किया गया है, और उसके बाद, result = __builtin_round(__builtin_sqrt(helper)) है। वैकल्पिक रूप से, helper = __builtin_sqrt(value()) और फिर result = __builtin_round(helper)

यह असंगतता से पता चलता है कि जीसीसी संकलन समय पर अभिव्यक्ति का मूल्यांकन करने में स्पष्ट रूप से सक्षम है और इसे constexpr के रूप में पेश करने के इच्छुक है। हालांकि इसे मानक में समर्थन नहीं मिल रहा है, लेकिन यह जीसीसी के बग ट्रैकर पर एक वृद्धि अनुरोध के रूप में रिपोर्टिंग के लायक हो सकता है।

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

1

यह छ ++ 4.8.2 पर काम करने लगता है:

static constexpr double value() { return 1.23; } 
static constexpr double root(double x) { return sqrt(x);} 
static constexpr double result = roundl(root(value())); 

दिलचस्प बात यह है कि अगर मैं round साथ roundl की जगह संकलक शिकायत:

error: ‘round(1.1090536506409416e+0)’ is not a constant expression 

यह भी काम करता है:

static constexpr double value() { return 1.23; } 
static constexpr double roundroot(double x) { return roundl(sqrt(x));} 
static constexpr double result = roundroot(value()); 

लेकिन फिर, केवल roundl के साथ और round के साथ नहीं। संबंधित __builtin_ संस्करणों (जो ये बस लपेटते हैं) का उपयोग करते समय यह सब भी सही है।

मैं अब देखने के लिए gcc स्रोत डाउनलोड कर रहा हूं लेकिन अभी तक "क्यों" का जवाब नहीं है।

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