जावास्क्रिप्ट में संख्या। Sign ()


101

आश्चर्य है कि क्या संख्या के संकेत ( साइनम फ़ंक्शन ) को खोजने के कोई अनैतिक तरीके हैं ?
स्पष्ट की तुलना में कम / तेज / अधिक सुरुचिपूर्ण समाधान हो सकते हैं

var sign = number > 0 ? 1 : number < 0 ? -1 : 0;

संक्षिप्त जवाब!

इसका उपयोग करें और आप सुरक्षित और तेज़ रहेंगे (स्रोत: moz )

if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };

आप प्रदर्शन और प्रकार- मजबूर तुलना को देखने के लिए चाहते हो सकता है बेला

लंबा समय बीत गया। इसके अलावा मुख्य रूप से ऐतिहासिक कारणों से है।


परिणाम

अभी के लिए हमारे पास ये उपाय हैं:


1. स्पष्ट और तेज

function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }

1.1। केबीसी से संशोधन - एक प्रकार का कम, अधिक कलाकार, छोटा [सबसे तेज़]

function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }

सावधान: sign("0") -> 1


2. सुरुचिपूर्ण, छोटा, इतना तेज़ नहीं [सबसे धीमा]

function sign(x) { return x && x / Math.abs(x); }

सावधानी: sign(+-Infinity) -> NaN ,sign("0") -> NaN

के रूप में Infinityजे एस में एक कानूनी संख्या इस समाधान पूरी तरह से सही प्रतीत नहीं होता है।


3. कला ... लेकिन बहुत धीमी [सबसे धीमी]

function sign(x) { return (x > 0) - (x < 0); }

4. बिट-शिफ्ट फास्ट का उपयोग करना
, लेकिनsign(-Infinity) -> 0

function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }

5. टाइप-सेफ [मेगाफ़ास्ट]

! ब्राउज़र (विशेष रूप से क्रोम के v8) की तरह लगता है कि कुछ जादू अनुकूलन करते हैं और यह समाधान दूसरों की तुलना में बहुत अधिक प्रदर्शनशील है, यहां तक ​​कि (1.1) की तुलना में इसमें 2 अतिरिक्त संचालन शामिल हैं और तार्किक रूप से कभी भी तेज नहीं हो सकता है।

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}

उपकरण

सुधारों का स्वागत है!


[ऑफॉप्टिक] स्वीकृत उत्तर

  • कला के लिए एंड्री टारनटोसोव - +100, लेकिन दुख की बात है कि यह स्पष्ट दृष्टिकोण की तुलना में लगभग 5 गुना धीमा है

  • Frédéric Hamidi - किसी भी तरह से सबसे अधिक उत्तर दिया (समय लिखने के लिए) और यह थोड़े शांत है, लेकिन यह निश्चित रूप से नहीं है कि चीजों को कैसे किया जाना चाहिए, imho। इसके अलावा यह सही ढंग से इन्फिनिटी नंबरों को नहीं संभालता है, जो कि संख्याएं भी हैं, आप जानते हैं।

  • केबीसी - स्पष्ट समाधान का सुधार है। वह क्रांतिकारी नहीं है, लेकिन सभी को एक साथ लेकर मैं इस दृष्टिकोण को सर्वश्रेष्ठ मानता हूं। उसके लिए वोट करें :)


3
बिंदु यह है कि कभी-कभी 0एक विशेष मामला होता है
विघटित

1
मैंने हर एल्गोरिथ्म का परीक्षण करने के लिए JSPerf परीक्षणों (विभिन्न प्रकार के इनपुट के साथ) का एक सेट बनाया है, जो यहां पाया जा सकता है: jsperf.com/signs परिणाम इस पोस्ट में सूचीबद्ध नहीं हो सकते हैं!
एल्बा मेंडेज़

2
@ निराश, उनमें से कौन सा? बेशक, यदि आप test everythingसंस्करण चलाते हैं, तो सेफ विशेष मानों का परीक्षण करने से इंकार कर देगा, इसलिए यह तेज होगा! only integersइसके बजाय परीक्षण चलाने का प्रयास करें । इसके अलावा, JSPerf सिर्फ अपना काम कर रहा है, यह पसंद करने की बात नहीं है। :)
अल्बा मेंडेज़

2
Jsperf परीक्षणों के अनुसार यह पता चलता है कि typeof x === "number"प्रदर्शन पर कुछ जादू है। कृपया, अधिक रन बनाने के लिए, विशेष रूप से FF, ओपेरा और IE को स्पष्ट करने के लिए।
विघटित

4
पूर्णता के लिए मैं एक नया परीक्षण जोड़ा jsperf.com/signs/7 के लिए Math.sign()(0 === 0 के रूप में तेजी से नहीं "सुरक्षित" के रूप में) जो FF25 में दिखाई दिया और क्रोम में आगामी है।
एलेक्स के।

जवाबों:



28

संख्या को उसके निरपेक्ष मान से विभाजित करना भी अपना संकेत देता है। शॉर्ट-सर्कुलेटिंग लॉजिकल और ऑपरेटर का उपयोग करने से हमें विशेष-केस की अनुमति मिलती है 0ताकि हम इसे विभाजित न करें:

var sign = number && number / Math.abs(number);

6
आप शायद इस var sign = number && number / Math.abs(number);मामले में चाहते हैंnumber = 0
NullUserException

@NullUserException, आप बिल्कुल सही हैं, 0विशेष- आवरण होने की आवश्यकता है। तदनुसार अद्यतन किया गया। धन्यवाद :)
Frédéric Hamidi

आप अभी के लिए सर्वश्रेष्ठ हैं। लेकिन मुझे उम्मीद है कि भविष्य में और भी जवाब मिलेंगे।
11

24

जिस कार्य के लिए आप देख रहे हैं उसे साइनम कहा जाता है , और इसे लागू करने का सबसे अच्छा तरीका है:

function sgn(x) {
  return (x > 0) - (x < 0);
}

3
रुको। इसमें गलती है: (x = -2; x <= 2; x ++) कंसोल.लॉग ((x> 1) - (x <1)); के लिए [-1, -1, -1, 0, 1] देता है (x = -2; x <= 2; x ++) कंसोल.लॉग ((x> 0) - (x <0)); सही देता है [-1, -1, 0, 1, 1]
विच्छेदित

13

क्या इसको जावास्क्रिप्ट (ECMAScript) के हस्ताक्षरित शून्य का समर्थन नहीं करना चाहिए? "मेगाफ़ास्ट" फ़ंक्शन में 0 के बजाय एक्स लौटाते समय यह काम करता है:

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}

यह ECMAScript के Math.sign ( MDN ) के मसौदे के साथ संगत बनाता है :

X का चिन्ह लौटाता है, यह दर्शाता है कि x धनात्मक, ऋणात्मक या शून्य है।

  • यदि x NaN है, तो परिणाम NaN है।
  • यदि x x0 है, तो परिणाम is0 है।
  • यदि x +0 है, तो परिणाम +0 है।
  • यदि x ऋणात्मक है और −0 नहीं है, तो परिणाम not1 है।
  • यदि x धनात्मक है और +0 नहीं है, तो परिणाम +1 है।

अविश्वसनीय रूप से तेज और दिलचस्प तंत्र, मैं प्रभावित हूं। अधिक परीक्षणों की प्रतीक्षा है।
केबीसी

10

उन लोगों के लिए जो नवीनतम ब्राउज़रों के साथ क्या कर रहे हैं, इसके लिए ES6 संस्करण में एक मूल Math.sign विधि है। आप यहां समर्थन की जांच कर सकते हैं

मूल रूप से यह रिटर्न -1, 1, 0याNaN

Math.sign(3);     //  1
Math.sign(-3);    // -1
Math.sign('-3');  // -1
Math.sign(0);     //  0
Math.sign(-0);    // -0
Math.sign(NaN);   // NaN
Math.sign('foo'); // NaN
Math.sign();      // NaN

4
var sign = number >> 31 | -number >>> 31;

सुपरफास्ट यदि आपको इन्फिनिटी की आवश्यकता नहीं है और जानते हैं कि संख्या एक पूर्णांक है, जो ओपनडेक -7 स्रोत में पाया जाता है: java.lang.Integer.signum()


1
यह -0.5 जैसे छोटे नकारात्मक अंशों के लिए विफल रहता है। (ऐसा लगता है कि स्रोत विशेष रूप से
इंटेगर के

1

मैंने सोचा कि मैं इसे सिर्फ मनोरंजन के लिए जोड़ूंगा:

function sgn(x){
  return 2*(x>0)-1;
}

0 और NaN
+ -1- इन्फिनिटी पर -1 काम करता है


1

एक समाधान जो सभी नंबरों पर काम करता है, 0और -0साथ ही साथ Infinityऔर -Infinity:

function sign( number ) {
    return 1 / number > 0 ? 1 : -1;
}

अधिक जानकारी के लिए प्रश्न " क्या +0 और -0 समान हैं? " देखें।


चेतावनी: इनमें से कोई भी जवाब नहीं, अब मानक सहित Math.signकेस 0बनाम पर काम करेगा -0। यह आपके लिए एक मुद्दा नहीं हो सकता है, लेकिन कुछ भौतिकी कार्यान्वयनों में यह महत्वपूर्ण हो सकता है।


0

आप नंबर को थोड़ा शिफ्ट कर सकते हैं और सबसे महत्वपूर्ण बिट (MSB) की जांच कर सकते हैं। यदि MSB 1 है तो संख्या ऋणात्मक है। यदि यह 0 है तो संख्या सकारात्मक है (या 0)।


@ NullUserException मैं अभी भी गलत हो सकता है लेकिन मेरे पढ़ने से "सभी बिटवाइज़ ऑपरेटरों के ऑपरेंड को 32-बिट पूर्णांक को बड़े-एंडियन क्रम में और दो के पूरक प्रारूप में परिवर्तित किया जाता है।" से लिया MDN
Brombomb

अभी भी ऐसा लगता है जैसे बहुत सारा काम; आपको अभी भी 1 और 0 को -1 और 1 में बदलना है, और 0 का भी ध्यान रखना है। अगर ओपी बस यही चाहता था, तो बस इस्तेमाल करना आसान होगाvar sign = number < 0 : 1 : 0
NullUserException

+1। हालांकि शिफ्ट करने की कोई जरूरत नहीं है, आप बस n & 0x80000000एक बिटमास्क की तरह कर सकते हैं । 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
davin

@davin क्या सभी नंबर उस बिटमास्क के साथ काम करने की गारंटी हैं? मैंने प्लग लगाया -5e32और वह टूट गया।
NullUserException 7

@NullUserException ఠ_ఠ, संख्याएँ जो मानकों को लागू करते समय एक ही संकेत रखती हैं ToInt32। यदि आप वहां पढ़ते हैं (खंड 9.5) तो एक मापांक है जो संख्याओं के मूल्य को प्रभावित करता है क्योंकि 32-बिट पूर्णांक की सीमा js संख्या प्रकार की सीमा से कम है। तो यह उन मूल्यों, या शिशुओं के लिए काम नहीं करेगा। मैं अभी भी जवाब पसंद है।
डेविन

0

मैं बस एक ही सवाल पूछने वाला था, लेकिन एक समाधान के आने से पहले ही मैंने लिखना शुरू कर दिया, यह प्रश्न पहले से ही मौजूद था, लेकिन मैंने इस समाधान को नहीं देखा।

(n >> 31) + (n > 0)

हालांकि यह एक ternary जोड़कर तेजी से प्रतीत होता है (n >> 31) + (n>0?1:0)


बहुत अच्छा। आपका कोड (1) की तुलना में काफी तेज लगता है। (n> 0? 1: 0) तेजी से बिना किसी प्रकार की कास्ट की जाती है। केवल विघटित होने का क्षण संकेत है (-इनफिनिटी) 0. अद्यतन परीक्षण।
विघटित

0

मार्टिज़न के जवाब के समान है

function sgn(x) {
    isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1));
}

मुझे यह अधिक पठनीय लगता है। इसके अलावा (या, आपके दृष्टिकोण के आधार पर, हालांकि), यह उन चीजों को भी नष्ट कर देता है जिन्हें एक संख्या के रूप में व्याख्या की जा सकती है; उदाहरण के लिए, यह -1तब दिया जाता है जब इसे प्रस्तुत किया जाता है '-5'


0

मुझे Math.signअपने संस्करण से -0 और 0 लौटने का कोई व्यावहारिक संकेत नहीं दिखता है:

function sign(x) {
    x = Number(x);
    if (isNaN(x)) {
        return NaN;
    }
    if (x === -Infinity || 1 / x < 0) {
        return -1;
    }
    return 1;
};

sign(100);   //  1
sign(-100);  // -1
sign(0);     //  1
sign(-0);    // -1

यह एक हस्ताक्षर कार्य नहीं है
विघटित

0

मैं जिन तरीकों के बारे में जानता हूं वे इस प्रकार हैं:

Math.sign (एन)

var s = Math.sign(n)

यह मूल फ़ंक्शन है, लेकिन फ़ंक्शन कॉल के ओवरहेड के कारण सभी में सबसे धीमा है। हालाँकि यह 'NaN' को संभालता है जहाँ नीचे वाले अन्य को केवल 0 मान सकते हैं (यानी Math.sign ('abc') NaN है)।

((n> 0) - (n <0))

var s = ((n>0) - (n<0));

इस मामले में केवल बाईं या दाईं ओर संकेत के आधार पर 1 हो सकता है। इसका परिणाम या तो 1-0(1), 0-1(-1), या 0-0(0) होता है।

क्रोम में अगले एक के साथ इस एक की गति गर्दन और गर्दन लगती है।

(एन >> 31) | (!! एन)

var s = (n>>31)|(!!n);

"साइन-प्रोपेगेटिंग राइट शिफ्ट" का उपयोग करता है। मूल रूप से 31 को शिफ्ट करने से साइन को छोड़कर सभी बिट्स गिर जाते हैं। यदि चिह्न सेट किया गया था, तो इसका परिणाम -1 है, अन्यथा यह 0. है। इसका अधिकार |बूलियन (0 या 1 [बीटीडब्ल्यू: गैर-संख्यात्मक स्ट्रिंग्स, जैसे !!'abc', इस मामले में 0 हो जाता है) के मान को परिवर्तित करके सकारात्मक के लिए परीक्षण करता है , और नहीं NaN]) फिर बिट्स को संयोजित करने के लिए एक बिटवाइज़ या ऑपरेशन का उपयोग करता है।

यह ब्राउज़र भर में सबसे अच्छा औसत प्रदर्शन है (कम से कम क्रोम और फ़ायरफ़ॉक्स में सबसे अच्छा), लेकिन उन सभी में सबसे तेज़ नहीं है। किसी कारण से, आईई में टर्नरी ऑपरेटर तेज होता है।

n n <0 -1? 1: 0

var s = n?n<0?-1:1:0;

किसी कारण से IE में सबसे तेज।

jsPerf

टेस्ट किए गए: https://jsperf.com/get-sign-from-value


0

मेरे दो सेंट, एक फ़ंक्शन के साथ, जो Math.sign के समान परिणाम लौटाता है, यानी साइन (-0) -> -0, साइन-इनफिनिटी) -> -इनफिनिटी, साइन (नल) -> 0 , संकेत (अपरिभाषित) -> NaN, आदि

function sign(x) {
    return +(x > -x) || (x && -1) || +x;
}

Jsperf मुझे परीक्षण या संशोधन करने की अनुमति नहीं देगा, आपको परीक्षण प्रदान करने में सक्षम नहीं होने के लिए खेद है (मैंने jsbench.github.io को एक कोशिश दी है, लेकिन परिणाम Jsperf की तुलना में एक दूसरे के बहुत करीब लगते हैं ...)

अगर कोई इसे Jsperf संशोधन में जोड़ सकता है, तो मुझे यह देखने की उत्सुकता होगी कि यह पहले दिए गए सभी विकल्पों की तुलना कैसे करता है ...

धन्यवाद!

जिम।

संपादित करें :

मुझे लिखना चाहिए:

function sign(x) {
    return +(x > -x) || (+x && -1) || +x;
}

(के (+x && -1)बजाय (x && -1)) sign('abc')ठीक से संभालने के लिए (-> NaN)


0

Math.sign IE 11 पर समर्थित नहीं है। मैं Math.sign उत्तर के साथ सर्वश्रेष्ठ उत्तर का संयोजन कर रहा हूं:

Math.sign = Math.sign || function(number){
    var sign = number ? ( (number <0) ? -1 : 1) : 0;
    return sign;
};

अब, कोई भी सीधे Math.sign का उपयोग कर सकता है।


1
आपने मुझे अपना प्रश्न अपडेट करने के लिए धक्का दिया। यह पूछे जाने पर 8 साल बीत गए। इसके अलावा मेरे jsfiddle को es6 और window.performance api में अपडेट किया गया। लेकिन मैं mozilla के संस्करण को पॉलीफ़िल के रूप में पसंद करता हूं क्योंकि यह Math.sign के प्रकार से मेल खाता है। प्रदर्शन आजकल ज्यादा चिंता का विषय नहीं है।
3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.