क्या C / C ++ में एक मानक साइन फ़ंक्शन (साइनम, sgn) है?


409

मैं एक फ़ंक्शन चाहता हूं जो नकारात्मक संख्याओं के लिए -1 और सकारात्मक संख्याओं के लिए +1 देता है। http://en.wikipedia.org/wiki/Sign_function अपने लेखन को लिखना काफी आसान है, लेकिन ऐसा लगता है कि इसे कहीं मानक पुस्तकालय में होना चाहिए।

संपादित करें: विशेष रूप से, मैं एक फंक्शन पर काम कर रहा था।


13
इसे 0 के लिए क्या लौटना चाहिए?
क्रेग मैकक्वीन

61
@ क्रेग मैकक्वीन; यह निर्भर करता है कि यह सकारात्मक शून्य है या नकारात्मक शून्य।
शाम

1
मैंने देखा कि आपने पूर्णांक के रूप में रिटर्न मान निर्दिष्ट किया था। क्या आप एक ऐसे समाधान की तलाश में हैं जो पूर्णांक या फ्लोटिंग पॉइंट नंबर लेता है?
मार्क बायर्स

6
@ysth @ क्रेग मैकक्वीन, झांकियों के लिए भी गलत, नहीं? sgn (x) की परिभाषा कहती है कि 0 पर लौटें x==0आईईईई 754 के अनुसार , नकारात्मक शून्य और सकारात्मक शून्य की तुलना बराबर होनी चाहिए।
RJFalconer

5
@ सिस्ट "यह सकारात्मक शून्य या नकारात्मक शून्य पर निर्भर करता है"। वास्तव में, ऐसा नहीं है।
RJFalconer

जवाबों:


506

आश्चर्यचकित किसी ने अभी तक टाइप-सी C ++ संस्करण पोस्ट नहीं किया है:

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

लाभ:

  • वास्तव में चिन्ह (-1, 0, या 1) को लागू करता है। कॉपीसिग्नल का उपयोग करके यहां कार्यान्वयन केवल -1 या 1 लौटाता है, जो कि साइनम नहीं है। इसके अलावा, यहां कुछ कार्यान्वयन इंट के बजाय एक फ्लोट (या टी) वापस कर रहे हैं, जो बेकार लगता है।
  • पूर्णांक 0 से और ऑर्डर करने योग्य के लिए इन्टस, फ्लोट्स, डबल्स, अहस्ताक्षरित शॉर्ट्स या कोई भी कस्टम प्रकार काम करता है।
  • तेज! copysignधीमा है, खासकर अगर आपको बढ़ावा देने और फिर संकीर्ण होने की आवश्यकता है। यह शाखा रहित है और उत्कृष्ट रूप से अनुकूलन करता है
  • मानकों का अनुपालन करने! बिटशिफ्ट हैक साफ-सुथरा है, लेकिन केवल कुछ बिट अभ्यावेदन के लिए काम करता है, और जब आपके पास अहस्ताक्षरित प्रकार होता है तो काम नहीं करता है। उपयुक्त होने पर इसे एक मैनुअल विशेषज्ञता के रूप में प्रदान किया जा सकता है।
  • सटीक! शून्य के साथ सरल तुलना मशीन के आंतरिक उच्च-सटीक प्रतिनिधित्व (जैसे x87 पर 80 बिट) को बनाए रख सकती है, और समय से पहले शून्य से बच सकती है।

चेतावनियां:

  • यह एक टेम्पलेट है इसलिए इसे कुछ परिस्थितियों में संकलित करने में अधिक समय लग सकता है।
  • जाहिरा तौर पर कुछ लोगों को लगता है कि एक नया, कुछ गूढ़ और बहुत धीमी मानक लाइब्रेरी फ़ंक्शन का उपयोग होता है जो वास्तव में साइनम को लागू नहीं करता है वह अधिक समझ में आता है।
  • जब अहस्ताक्षरित प्रकार के लिए त्वरित किया जाता है तो < 0चेक का हिस्सा जीसीसी की -Wtype-limitsचेतावनी को ट्रिगर करता है । आप कुछ अतिभारों का उपयोग करके इससे बच सकते हैं:

    template <typename T> inline constexpr
    int signum(T x, std::false_type is_signed) {
        return T(0) < x;
    }
    
    template <typename T> inline constexpr
    int signum(T x, std::true_type is_signed) {
        return (T(0) < x) - (x < T(0));
    }
    
    template <typename T> inline constexpr
    int signum(T x) {
        return signum(x, std::is_signed<T>());
    }

    (जो पहले कैविएट का एक अच्छा उदाहरण है।)


18
@ मन: जीसीसी केवल अब (4.5) टेम्पलेट कार्यों के लिए तात्कालिकता की संख्या के लिए लागत को कम करना बंद कर दिया है, और वे मैन्युअल रूप से लिखित कार्यों या मानक सी प्रीप्रोसेसर की तुलना में पार्स और तत्काल के लिए बहुत अधिक महंगे हैं। डुप्लिकेट इंस्टेंटेशंस को हटाने के लिए लिंकर को भी अधिक काम करना पड़ता है। टेम्प्लेट # शामिल-इन- # को भी प्रोत्साहित करते हैं, जिससे निर्भरता की गणना में अधिक समय लगता है और छोटे (अक्सर कार्यान्वयन, इंटरफ़ेस नहीं) अधिक फ़ाइलों को फिर से संकलित करने के लिए मजबूर करता है।

15
@ जो: हाँ, और अभी भी कोई ध्यान देने योग्य लागत नहीं है। C ++ टेम्प्लेट का उपयोग करता है, यह केवल कुछ है जिसे हम सभी को समझना, स्वीकार करना और प्राप्त करना है।
22

42
रुको, क्या यह "मैलापन धीमा है" व्यापार ...? वर्तमान संकलक (g ++ 4.6+, clang ++ 3.0) का उपयोग करते हुए, मेरे लिए उत्कृष्ट कोड std::copysignमें परिणाम प्रतीत होता है : 4 निर्देश (इनलाइन), कोई शाखा नहीं, पूरी तरह से FPU का उपयोग करना। इस उत्तर में दी गई रेसिपी, इसके विपरीत, बहुत बदतर कोड (कई और निर्देश, जिसमें एक
बहुतायत से

14
@snogglethorpe: यदि आप copysignएक इंट पर कॉल कर रहे हैं तो यह फ्लोट / डबल को बढ़ावा देता है, और वापसी पर फिर से संकीर्ण होना चाहिए। आपका कंपाइलर उस प्रचार को अनुकूलित कर सकता है, लेकिन मुझे कुछ भी सुझाव नहीं मिल सकता है जो मानक द्वारा गारंटीकृत हो। इसके अलावा साइनसीम के माध्यम से साइनम लागू करने के लिए आपको मैन्युअल रूप से 0 केस को संभालने की आवश्यकता है - कृपया सुनिश्चित करें कि आप किसी भी प्रदर्शन तुलना में इसे शामिल करते हैं।

53
पहला संस्करण शाखा रहित नहीं है। लोग ऐसा क्यों सोचते हैं कि एक अभिव्यक्ति में प्रयुक्त तुलना एक शाखा उत्पन्न नहीं करेगी? यह ज्यादातर आर्किटेक्चर पर होगा। केवल प्रोसेसर जिसमें एक cmove (या पूर्वनिर्धारण) होता है, शाखाविहीन कोड उत्पन्न करेगा, लेकिन वे इसे टर्नरी के लिए भी करेंगे या यदि / यदि यह एक जीत है तो।
पैट्रिक श्ल्टर

271

मुझे इसके लिए एक मानक कार्य की जानकारी नहीं है। हालांकि यह लिखने का एक दिलचस्प तरीका है:

(x > 0) - (x < 0)

यहाँ यह करने के लिए एक और अधिक पठनीय तरीका है:

if (x > 0) return 1;
if (x < 0) return -1;
return 0;

यदि आपको टर्नरी ऑपरेटर पसंद है तो आप यह कर सकते हैं:

(x > 0) ? 1 : ((x < 0) ? -1 : 0)

7
मार्क रैनसम, आपके भाव गलत परिणाम देते हैं x==0
अवकर

3
@Svante: "प्रत्येक ऑपरेटर <, >... 1 का उत्पादन करेगा यदि निर्दिष्ट संबंध सत्य है और 0 यदि यह गलत है"
स्टीफन कैनन

11
@ शांते: बिल्कुल नहीं। का एक मूल्य 0"झूठा" है; कोई अन्य मूल्य "सच" है; हालाँकि, संबंधपरक और समानता ऑपरेटर हमेशा लौटते हैं 0या 1(मानक 6.5.8 और 6.5.9 देखें)। - अभिव्यक्ति a * (x == 42)का मूल्य 0या तो है या a
दोपहर

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

6
क्या किसी ने वास्तव में चेक किया है कि वास्तविक प्लेटफ़ॉर्म पर GCC / G ++ / किसी अन्य संकलक का क्या कोड है? मेरा अनुमान है कि "शाखा रहित" संस्करण एक के बजाय दो शाखाओं का उपयोग करता है। बिटशफ्टिंग संभवतः बहुत तेज़ है - और प्रदर्शन के मामले में अधिक पोर्टेबल है।
जोर्गन फॉग

192

एक C99 गणित लाइब्रेरी फ़ंक्शन है जिसे कॉपसाइन () कहा जाता है, जो एक तर्क से संकेत लेता है और दूसरे से पूर्ण मान:

result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double

मूल्य के संकेत के आधार पर आपको +/- 1.0 का परिणाम देगा। ध्यान दें कि फ्लोटिंग पॉइंट जीरो पर हस्ताक्षर किए गए हैं: (+0) +1 का उत्पादन करेगा, और (-0) -1 का उत्पादन करेगा।


57
यह सबसे लोकप्रिय उत्तर को नीचा दिखाती है। अचंभे में छोड़ दिया है कि एसओ समुदाय एक मानक पुस्तकालय समारोह का उपयोग करने के लिए एक हैक पसंद करते हैं लगता है। प्रोग्रामिंग के देवता आप सभी की निंदा कर सकते हैं जो भाषा के मानकों से अपरिचित होशियार प्रोग्रामर द्वारा उपयोग की जाने वाली हैक को समझने की कोशिश कर रहे हैं। हाँ, मुझे पता है कि यह मुझे एसओ पर प्रतिनिधि के रूप में एक टन खर्च करने जा रहा है, लेकिन मैं आपके बाकी हिस्सों की तुलना में आने वाले समय के साथ आगे बढ़ना चाहूंगा ...
उच्च प्रदर्शन मार्क

34
यह करीब है, लेकिन यह शून्य के लिए गलत उत्तर देता है (कम से कम प्रश्न में विकिपीडिया लेख के अनुसार)। हालांकि अच्छा सुझाव है। वैसे भी +1।
मार्क बायर्स

4
यदि आप एक पूर्णांक चाहते हैं, या यदि आप शून्य के लिए सटीक हस्ताक्षर परिणाम चाहते हैं, तो मुझे मार्क बायर्स का उत्तर पसंद है, जो कि बहुत ही सुंदर है! यदि आप उपर्युक्त के बारे में परवाह नहीं करते हैं, तो कॉपीसाइन () में आवेदन के आधार पर प्रदर्शन में कमी हो सकती है - अगर मैं एक महत्वपूर्ण लूप का अनुकूलन कर रहा था, तो मैं दोनों की कोशिश करूंगा।
आने वाली रात

10
1) C99 हर जगह पूरी तरह से समर्थित नहीं है (VC ++ पर विचार करें); 2) यह एक C ++ प्रश्न भी है। यह एक अच्छा जवाब है, लेकिन ऊपरवाला भी काम करता है, और अधिक व्यापक रूप से लागू होता है।
पावेल मिनाएव

5
उद्धारकर्ता! -0.0 और 0.0 के बीच निर्धारित करने के लिए एक रास्ता चाहिए
Waलफुर वेज

79

ऐसा लगता है कि अधिकांश उत्तर मूल प्रश्न से चूक गए।

क्या C / C ++ में एक मानक साइन फ़ंक्शन (साइनम, sgn) है?

मानक पुस्तकालय में नहीं, हालांकि वहाँ है copysignजो लगभग उसी तरह से इस्तेमाल किया जा सकता है copysign(1.0, arg)और इसमें एक सच्चा संकेत कार्य है boost, जो मानक का हिस्सा हो सकता है।

    #include <boost/math/special_functions/sign.hpp>

    //Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
    template <class T>
    inline int sign (const T& z);

http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html


5
यह सबसे अधिक मत देने वाला उत्तर होना चाहिए, क्योंकि यह प्रश्न में पूछे गए प्रश्नों का निकटतम संभव समाधान देता है।
बार्टोसजप

मैं पिछले कुछ मिनटों से सोच रहा था कि मानक पुस्तकालय में साइन फंक्शन क्यों नहीं है। यह सिर्फ इतना सामान्य है - निश्चित रूप से गामा फ़ंक्शन की तुलना में अधिक उपयोग किया जाता है जो कि सेमीथ हेडर में पाया जा सकता है।
ताओजी

4
इसी तरह के सवालों के लिए मुझे अक्सर जो स्पष्टीकरण मिलता है वह है "यह अपने आप को लागू करने के लिए पर्याप्त आसान है" कौन सा आईएमओ एक अच्छा कारण नहीं है। यह पूरी तरह से उन समस्याओं की पुष्टि करता है जहां मानकीकरण, अप्रकाशित धार के मामले, और इस तरह के व्यापक रूप से उपयोग किए जाने वाले उपकरण को कहां रखा जाए।
२०:३५ पर कैटस्कूल

77

जाहिर है, मूल पोस्टर के सवाल का जवाब नहीं है। कोई मानक C ++ sgnफ़ंक्शन नहीं है।


2
@ एसआर_ आप सही नहीं हैं। copysign()अपना पहला पैरामीटर 0.0 नहीं बनाएंगे यदि दूसरा 0.0 है। दूसरे शब्दों में, जॉन सही है।
एलेक्सिस विलके

29

उपरोक्त समाधानों की तुलना में तेज़, जिसमें सबसे अधिक रेट किए गए हैं:

(x < 0) ? -1 : (x > 0)

1
X किस प्रकार का है? या आप एक #define का उपयोग कर रहे हैं?
मौका

3
आपका प्रकार तेज नहीं है। यह काफी बार कैश मिस का कारण बनेगा।
जेफरी ड्रेक

19
कैश मिस? मुझे यकीन नहीं है कि कैसे शायद आपका मतलब ब्रांच मिसप्रिंटेड था?
कैटस्कुल

2
मुझे ऐसा लगता है कि इससे पूर्णांक और बूलियन प्रकारों को भ्रमित करने की चेतावनी मिलेगी!
सर्गियोल

यह शाखा के साथ कैसे तेज होगा?
निक

29

क्या C / C ++ में एक मानक साइन फ़ंक्शन (साइनम, sgn) है?

हां, परिभाषा पर निर्भर करता है।

C99 और बाद में signbit()मैक्रो में है<math.h>

int signbit(वास्तविक-अस्थायी x); मैक्रो रिटर्न एक अशून्य मूल्य यदि और केवल यदि अपने तर्क मूल्य के हस्ताक्षर नकारात्मक है। C11 §7.12.3.6
signbit


फिर भी ओपी कुछ अलग करना चाहता है।

मैं एक फ़ंक्शन चाहता हूं जो नकारात्मक संख्याओं के लिए -1 और सकारात्मक संख्याओं के लिए +1 देता है। ... एक समारोह चल रहा है।

#define signbit_p1_or_n1(x)  ((signbit(x) ?  -1 : 1)

और गहरा:

पोस्ट निम्नलिखित मामलों में विशिष्ट नहीं है x = 0.0, -0.0, +NaN, -NaN:।

एक क्लासिक signum()रिटर्न +1पर x>0, -1पर x<0और 0पर x==0

कई उत्तर पहले ही कवर कर चुके हैं, लेकिन पता नहीं है x = -0.0, +NaN, -NaN। कई एक पूर्णांक बिंदु के लिए तैयार किए जाते हैं, जिनमें आमतौर पर नॉट-ए-नंबर ( NaN ) और -0.0 का अभाव होता है ।

विशिष्ट उत्तर signnum_typical() ऑन की तरह कार्य -0.0, +NaN, -NaNकरते हैं, वे वापस लौटते हैं 0.0, 0.0, 0.0

int signnum_typical(double x) {
  if (x > 0.0) return 1;
  if (x < 0.0) return -1;
  return 0;
}

इसके बजाय, मैं इस कार्यक्षमता का प्रस्ताव करता हूं: पर -0.0, +NaN, -NaN, यह वापस लौटता है -0.0, +NaN, -NaN

double signnum_c(double x) {
  if (x > 0.0) return 1.0;
  if (x < 0.0) return -1.0;
  return x;
}

1
आह, वास्तव में मैं क्या कर रहा हूँ। यह सिर्फ फेरो स्मालटॉक github.com/pharo-project/pharo/pull/1835 में बदल गया और मुझे आश्चर्य हुआ कि क्या किसी तरह का मानक (IEC 60559 या ISO 10967) नकारात्मक शून्य और नैनो व्यवहार के लिए व्यवहार तय कर रहा था ... मुझे पसंद है जावास्क्रिप्ट साइन डेवलपर
pm.millailla.org/en-US/docs/Web/JavaScript/Reference/…

16

ब्रांचिंग के बिना इसे करने का एक तरीका है, लेकिन यह बहुत सुंदर नहीं है।

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));

http://graphics.stanford.edu/~seander/bithacks.html

उस पृष्ठ पर अन्य रोचक, अति-चतुर सामान भी ...


1
यदि मैं लिंक को सही ढंग से पढ़ता हूं जो केवल -1 या 0. रिटर्न करता है, यदि आप -1, 0 या +1 चाहते हैं तो यह है sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));या sign = (v > 0) - (v < 0);
जेड बोसॉन

1
इसका तात्पर्य यह है कि vएक पूर्णांक प्रकार है जो int
phuclv

12

यदि आप चाहते हैं कि सभी को संकेत का परीक्षण करना है, तो साइनबिट का उपयोग करें (यदि इसका तर्क नकारात्मक संकेत है तो सच है)। निश्चित नहीं है कि आप विशेष रूप से -1 या +1 क्यों चाहते हैं; कॉपसाइन इसके लिए अधिक सुविधाजनक है, लेकिन ऐसा लगता है कि यह कुछ प्लेटफार्मों पर नकारात्मक शून्य के लिए +1 को नकारात्मक शून्य के लिए केवल आंशिक समर्थन के साथ लौटा देगा, जहां साइनबिट संभवतः सही मायने में वापस आ जाएगी।


7
कई गणितीय अनुप्रयोग हैं जिनमें साइन (x) आवश्यक है। नहीं तो मैं बस करूँगा if (x < 0)
मौका

5

सामान्य तौर पर, C / C ++ में कोई मानक साइनम फ़ंक्शन नहीं होता है, और इस तरह के मूलभूत फ़ंक्शन की कमी आपको इन भाषाओं के बारे में बहुत कुछ बताती है।

इसके अलावा, मेरा मानना ​​है कि इस तरह के फ़ंक्शन को परिभाषित करने के लिए सही दृष्टिकोण के बारे में दोनों बहुसंख्यक दृष्टिकोण एक तरह से सही हैं, और इसके बारे में "विवाद" वास्तव में एक गैर-तर्क है जब आप दो महत्वपूर्ण कैविट्स को ध्यान में रखते हैं:

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

  • फ्लोटिंग पॉइंट प्रकारों में एक भी सटीक शून्य मान नहीं होता है: +0.0 को "अनंत से ऊपर शून्य", और -0.0 को "अनंत से नीचे शून्य" के रूप में व्याख्या किया जा सकता है। यही कारण है कि शून्य से तुलना करने वाले को दोनों मूल्यों के खिलाफ आंतरिक रूप से जांच करनी चाहिए, और एक अभिव्यक्ति जैसी x == 0.0खतरनाक हो सकती है।

सी के बारे में, मुझे लगता है कि अभिन्न प्रकारों के साथ सबसे अच्छा तरीका वास्तव में उपयोग करना है (x > 0) - (x < 0) अभिव्यक्ति है, क्योंकि इसे शाखा-मुक्त फैशन में अनुवादित किया जाना चाहिए, और इसके लिए केवल तीन बुनियादी कार्यों की आवश्यकता होती है। सबसे अच्छा इनलाइन फ़ंक्शन परिभाषित करते हैं जो तर्क प्रकार से मेल खाते रिटर्न प्रकार को लागू करते हैं, और define _Genericइन कार्यों को एक सामान्य नाम पर मैप करने के लिए एक C11 जोड़ते हैं ।

चल बिन्दु मूल्यों के साथ, मैं सी 11 के आधार पर लगता है कि इनलाइन कार्यों copysignf(1.0f, x), copysign(1.0, x)और copysignl(1.0l, x)जाने का रास्ता नहीं है, बस क्योंकि वे भी कर रहे हैं अत्यधिक संभावना शाखा से मुक्त होने के लिए, और इसके अलावा एक चल बिन्दु में पूर्णांक पीछे से परिणाम कास्टिंग की आवश्यकता नहीं है मूल्य। आपको संभवतः प्रमुख रूप से टिप्पणी करनी चाहिए कि साइनम के आपके फ़्लोटिंग पॉइंट इम्प्लीमेंटेशन फ़्लोटिंग पॉइंट ज़ीरो वैल्यूज़ की ख़ासियतों की वजह से ज़ीरो वापस नहीं आएंगे, समय के विचार को संसाधित करेंगे, और यह भी क्योंकि सही -1 / + प्राप्त करने के लिए यह फ़्लोटिंग पॉइंट अंकगणितीय में बहुत उपयोगी है। 1 संकेत, यहां तक ​​कि शून्य मानों के लिए भी।


5

संक्षेप में सी की मेरी कॉपी से एक मानक फ़ंक्शन के अस्तित्व का पता चलता है जिसे कॉपसाइन कहा जाता है जो उपयोगी हो सकता है। ऐसा लग रहा है कि कॉप्सिग्ने (1.0, -2.0) -1.0 पर लौटेगा और कॉप्सिग्ने (1.0, 2.0) +1.0 पर लौटेगा।

बहुत करीब है?


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

5
कॉपिसाइन आईएसओ सी (सी 99) और पोसिक्स मानकों दोनों में है। देखें opengroup.org/onlinepubs/000095399/functions/copysign.html
LHF

3
Lhf ने क्या कहा। विजुअल स्टूडियो सी मानक का संदर्भ नहीं है।
स्टीफन कैनन

3

नहीं, यह सी ++ में मौजूद नहीं है, जैसे मैटलैब में। मैं इसके लिए अपने कार्यक्रमों में एक मैक्रो का उपयोग करता हूं।

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )

5
C ++ में मैक्रोज़ पर टेम्प्लेट को प्राथमिकता देनी चाहिए।
रुस्लान

C में, कोई टेम्पलेट नहीं है ...... helloacm.com/how-to-implement-the-sgn-function-in-c
डॉक्टरलाई २०'१६

मुझे लगा कि यह एक अच्छा जवाब है तो मैंने अपने कोड को देखा और यह पाया: #define sign(x) (((x) > 0) - ((x) < 0))जो अच्छा भी है।
मिशेल रूजिक

1
इनलाइन फ़ंक्शन C में एक मैक्रो से बेहतर है, और C ++ टेम्पलेट में बेहतर है
phuclv

3

नीचे दिए गए अधिभार के साथ स्वीकृत उत्तर वास्तव में ट्रिगर नहीं होता है -प्रकार-सीमाएँ

template <typename T> inline constexpr
  int signum(T x, std::false_type) {
  return T(0) < x;
}

template <typename T> inline constexpr
  int signum(T x, std::true_type) {
  return (T(0) < x) - (x < T(0));
}

template <typename T> inline constexpr
  int signum(T x) {
  return signum(x, std::is_signed<T>());
}

C ++ 11 के लिए एक विकल्प हो सकता है।

template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T const x) {
    return T(0) < x;  
}

template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T const x) {
    return (T(0) < x) - (x < T(0));  
}

मेरे लिए यह जीसीसी 5.3.1 पर किसी भी चेतावनी को ट्रिगर नहीं करता है।


-Wunused-parameterचेतावनी से बचने के लिए बस अनाम पैरामीटर का उपयोग करें।
जोनाथन वेकली

यह वास्तव में बहुत सच है। मैंने यह खो दिया। हालाँकि, मुझे C ++ 11 विकल्प अधिक पसंद है।
सैमवोनडॉट

2

बिट ऑफ-टॉपिक, लेकिन मैं इसका उपयोग करता हूं:

template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
    return (a > b) - (a < b);
}

template<typename T>
constexpr int sgn(const T &a) noexcept{
    return sgn(a, T(0));
}

और मुझे पहला फ़ंक्शन मिला - दो तर्कों के साथ, "मानक" sgn () से बहुत अधिक उपयोगी होने के लिए, क्योंकि यह इस तरह कोड में सबसे अधिक बार उपयोग किया जाता है:

int comp(unsigned a, unsigned b){
   return sgn( int(a) - int(b) );
}

बनाम

int comp(unsigned a, unsigned b){
   return sgn(a, b);
}

अहस्ताक्षरित प्रकारों के लिए कोई कास्ट नहीं है और कोई अतिरिक्त माइनस नहीं है।

वास्तव में मैं sgn का उपयोग कर कोड का यह टुकड़ा है ()

template <class T>
int comp(const T &a, const T &b){
    log__("all");
    if (a < b)
        return -1;

    if (a > b)
        return +1;

    return 0;
}

inline int comp(int const a, int const b){
    log__("int");
    return a - b;
}

inline int comp(long int const a, long int const b){
    log__("long");
    return sgn(a, b);
}

1

सवाल पुराना है, लेकिन अब इस तरह का वांछित कार्य है। मैंने एक रैपर जोड़ा, न कि शिफ्ट और डिक।

सटीक वांछित व्यवहार प्राप्त करने के लिए आप C99 से साइनबिट के आधार पर एक आवरण फ़ंक्शन का उपयोग कर सकते हैं (नीचे कोड देखें)।

लौटाता है कि क्या x का चिन्ह ऋणात्मक है।
यह शिशुओं, NaN और शून्य पर लागू किया जा सकता है (यदि शून्य अहस्ताक्षरित है, तो इसे सकारात्मक माना जाता है

#include <math.h>

int signValue(float a) {
    return ((!signbit(a)) << 1) - 1;
}

NB: मैं ऑपरेंड का उपयोग नहीं करता हूं ("!") क्योंकि साइनबिट का रिटर्न मान 1 होना निर्दिष्ट नहीं है (भले ही उदाहरण हमें यह हमेशा ऐसा लगता है) लेकिन नकारात्मक संख्या के लिए सही है:


यदि x का चिह्न ऋणात्मक है, तो वापसी मान एक गैर-शून्य मान (सत्य); और शून्य (असत्य) अन्यथा।

फिर मैं बाएं शिफ्ट के साथ दो से गुणा करता हूं ("<< 1") जो हमें एक सकारात्मक संख्या के लिए 2 और एक नकारात्मक के लिए 0 और अंत में 1 और -1 के लिए क्रमशः 1 और -1 प्राप्त करने के लिए 1 से 1 तक की गिरावट के रूप में सकारात्मक और नकारात्मक संख्याओं के लिए अनुरोध करेगा ओपी।


0 तब भी सकारात्मक होगा ... जो ओपी चाहता था या नहीं हो सकता है ...
एंटी हापला

अच्छी तरह से हम कभी नहीं पता हो सकता है कि ओपी वास्तव में क्या चाहता था अगर n = 0 ...!
एंटोनिन GAVREL

0

जबकि स्वीकृत उत्तर में पूर्णांक समाधान काफी सुरुचिपूर्ण है, यह मुझे परेशान करता है कि यह NAN को दोहरे प्रकारों में वापस करने में सक्षम नहीं होगा, इसलिए मैंने इसे थोड़ा संशोधित किया।

template <typename T> double sgn(T val) {
    return double((T(0) < val) - (val < T(0)))/(val == val);
}

ध्यान दें कि एक हार्ड कोडित के विपरीत एक अस्थायी बिंदु NAN को वापस NANकरने से कुछ कार्यान्वयन में साइन बिट सेट होने का कारण बनता है , इसलिए आउटपुट के लिए val = -NANऔर val = NANसमान होने जा रहे हैं कोई फर्क नहीं पड़ता कि क्या (यदि आप एक " nan" आउटपुट को पसंद करते हैं, तो आप -nanडाल सकते हैं एक abs(val)वापसी से पहले ...)



0

यहाँ एक शाखा-अनुकूल कार्यान्वयन है:

inline int signum(const double x) {
    if(x == 0) return 0;
    return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

जब तक आपके डेटा में संख्याओं के आधे के रूप में शून्य नहीं है, यहां शाखा भविष्यवक्ता सबसे आम के रूप में शाखाओं में से एक का चयन करेगा। दोनों शाखाओं में केवल सरल ऑपरेशन शामिल हैं।

वैकल्पिक रूप से, कुछ संकलक और सीपीयू आर्किटेक्चर पर पूरी तरह से शाखा रहित संस्करण तेज हो सकता है:

inline int signum(const double x) {
    return (x != 0) * 
        (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

यह IEEE 754 दोहरे परिशुद्धता द्विआधारी फ्लोटिंग-पॉइंट प्रारूप के लिए काम करता है : बाइनरी 64


-1
int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

यह फ़ंक्शन मानता है:

  • binary32 फ्लोटिंग पॉइंट नंबरों का प्रतिनिधित्व
  • एक संकलक जो एक नामित संघ का उपयोग करते समय सख्त अलियासिंग नियम के बारे में एक अपवाद बनाता है

3
यहां अभी भी कुछ बुरी धारणाएं हैं। उदाहरण के लिए, मुझे विश्वास नहीं है कि फ्लोट की समाप्ति की पूर्णता की समाप्ति की गारंटी है। ILP64 का उपयोग करके आपका चेक किसी भी आर्किटेक्चर पर विफल रहता है। वास्तव में, आप बस फिर से लागू कर रहे हैं copysign; अगर आप static_assertC ++ 11 का उपयोग कर रहे हैं , और वास्तव में उपयोग कर सकते हैं copysign


-3

जब आप बस ऐसा कर सकते हैं तो टर्नरी ऑपरेटर और यदि-और का उपयोग करें

#define sgn(x) x==0 ? 0 : x/abs(x)

3
आपकी परिभाषा एक टर्नरी ऑपरेटर का भी उपयोग करती है।
मार्टिन आर

हां निश्चित रूप से, लेकिन यह शून्य और गैर-शून्य संख्याओं को अलग करने के लिए बस एक टर्नरी ऑपरेटर का उपयोग करता है। दूसरों के संस्करणों में सकारात्मक, नकारात्मक और शून्य को अलग करने के लिए नेस्टेड टर्नरी ऑप्स शामिल हैं।
जगप्रीत

पूर्णांक विभाजन का उपयोग करना बहुत ही अक्षम है और एब्स () केवल पूर्णांकों के लिए है।
मिशेल रूज़िक

अपरिहार्य व्यवहार जब संभव हो x == INT_MIN
chux -
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.