2012-05-04 16 views
12

(टिप्पणी: के बाद से ओपी कभी नहीं स्पष्ट रूप से की दिशा में 0 या -Infinity गोलाई निर्दिष्ट this other question के रूप में ही नहीं)जावा: मैं पूर्णांक विभाजन कैसे कर सकता हूं जो कि 0 की बजाय अनंतता की ओर है?

JLS 15.17.2 का कहना है कि शून्य की ओर पूर्णांक विभाजन दौर। अगर मुझे सकारात्मक divisors के लिए floor() जैसा व्यवहार चाहिए (मुझे नकारात्मक divisors के व्यवहार के बारे में परवाह नहीं है), यह प्राप्त करने का सबसे आसान तरीका क्या है जो सभी इनपुट के लिए संख्यात्मक रूप से सही है?

int ifloor(int n, int d) 
{ 
    /* returns q such that n = d*q + r where 0 <= r < d 
    * for all integer n, d where d > 0 
    * 
    * d = 0 should have the same behavior as `n/d` 
    * 
    * nice-to-have behaviors for d < 0: 
    * option (a). same as above: 
    *  returns q such that n = d*q + r where 0 <= r < -d 
    * option (b). rounds towards +infinity: 
    *  returns q such that n = d*q + r where d < r <= 0 
    */ 
} 

long lfloor(long n, long d) 
{ 
    /* same behavior as ifloor, except for long integers */ 
} 

(अद्यतन: मैं दोनों के लिए int और long अंकगणित एक समाधान करना चाहते हैं।)

+0

यह * एक डुप्लिकेट होना है, लेकिन मुझे यह नहीं मिल रहा है, और यदि यह डुप्लिकेट नहीं है तो मैं पूरी तरह से हैरान हूं कि यह स्टैक ओवरफ्लो के 3+ वर्षों के बाद अभी तक नहीं आया है। –

+0

शेष के लिए 'd <0' स्थितियों में, मुझे लगता है कि आपके पास कुछ उलटा संकेत हैं। ऐसा लगता है कि आप विकल्प (ए) और 'd

+0

सही: धन्यवाद, मेरा मतलब divisor का सकारात्मक संस्करण था। (और यह + अनंतता की ओर घूम रहा होना चाहिए) –

उत्तर

6

(मैं int रों के लिए जवाब के बाद से long रों के लिए सब कुछ कर रहा हूँ में एक ही है, बस स्थानापन्न int हर long और Integer हर Long के लिए के लिए।)

आप कर सकते थे बस Math.floor एक डबल विभाजन परिणाम, अन्यथा ...

01,235,

मूल जवाब:

return n/d - ((n % d != 0) && ((n<0)^(d<0)) ? 1 : 0); 

अनुकूलित जवाब:

public static long lfloordiv(long n, long d) { 

    long q = n/d; 
    if(q*d == n) return q; 
    return q - ((n^d) >>> (Long.SIZE-1)); 
} 

(। पूर्णता के लिए, एक ROUND_FLOOR एक साथ BigDecimal गोलाई मोड का उपयोग भी एक विकल्प है)

न्यू संपादित करें : अब मैं यह देखने की कोशिश कर रहा हूं कि इसे मज़े के लिए अनुकूलित किया जा सकता है। Mark's answer का उपयोग सबसे अच्छा मैं अब तक है:

public static long lfloordiv2(long n, long d){ 

    if(d >= 0){ 
     n = -n; 
     d = -d; 
    } 
    long tweak = (n >>> (Long.SIZE-1)) - 1; 
    return (n + tweak)/d + tweak; 
} 

(ऊपर से सस्ता संचालन का उपयोग करता है, लेकिन थोड़ा लंबा बाईटकोड (29 बनाम 26))।

+0

कृपया मुझे Math.floor की ओर न देखें। यदि यह 'int' चर के लिए ठीक से काम करता है (जो कि मैं निश्चित नहीं हूं), यह सटीकता की कमी के कारण' लंबे' चर के लिए काम नहीं करेगा। –

+0

मैं एक मिनट में दरवाजा बाहर जा रहा हूं लेकिन अगर मैं इसे सोमवार को शुद्धता के लिए देख सकता हूं, तो मैं +1 कर दूंगा। धन्यवाद + एक अच्छा सप्ताहांत है .... –

+2

अच्छा! एक मामूली obfuscating अनुकूलन: '(एन <0)^(डी <0)' 'n^डी <0' के साथ बदलें। कंपाइलर _might_ आपके लिए यह अनुकूलन करता है, लेकिन मुझे शक है। –

7

यदि आप तृतीय-पक्ष पुस्तकालयों का उपयोग कर सकते हैं, Guava में यह है: IntMath.divide(int, int, RoundingMode.FLOOR) और LongMath.divide(int, int, RoundingMode.FLOOR)। (प्रकटीकरण: मैं अमरूद में योगदान देता हूं।)

यदि आप इसके लिए किसी तृतीय-पक्ष लाइब्रेरी का उपयोग नहीं करना चाहते हैं, तो भी आप कार्यान्वयन को देख सकते हैं।

+0

यह सुनना अच्छा है - अमरूद एक बहुत प्रतिष्ठित पुस्तकालय है। –

+0

गुवा में युगल के लिए विभाजन समारोह क्यों नहीं था? – voipp

+0

@voipp: आप इसके साथ क्या करेंगे? यह सामान्य डबल डिवीजन से अलग कैसे होगा? –

6

इस के लिए एक साफ साफ सूत्र है जो n < 0 और d > 0 पर काम करता है: एन के बिटवाईयर पूरक को लें, विभाजन करें, और उसके परिणामस्वरूप थोड़ा सा पूरक लें।

int ifloordiv(int n, int d) 
{ 
    if (n >= 0) 
     return n/d; 
    else 
     return ~(~n/d); 
} 

शेष के लिए, एक ऐसी ही निर्माण कार्य (अर्थ है कि हमेशा की तरह अपरिवर्तनीय ifloordiv(n, d) * d + ifloormod(n, d) == n संतुष्ट है में ifloordiv के साथ संगत) एक परिणाम के रेंज [0, d) में हमेशा से है कि दे रही है।

int ifloormod(int n, int d) 
{ 
    if (n >= 0) 
     return n % d; 
    else 
     return d + ~(~n % d); 
} 

नकारात्मक divisors के लिए, सूत्र काफी साफ नहीं हैं। यहां ifloordiv और ifloormod के विस्तृत संस्करण दिए गए हैं जो नकारात्मक divisors के लिए आपके 'अच्छा-से-' व्यवहार विकल्प (बी) का पालन करते हैं।

int ifloordiv(int n, int d) 
{ 
    if (d >= 0) 
     return n >= 0 ? n/d : ~(~n/d); 
    else 
     return n <= 0 ? n/d : (n - 1)/d - 1; 
} 

int ifloormod(int n, int d) 
{ 
    if (d >= 0) 
     return n >= 0 ? n % d : d + ~(~n % d); 
    else 
     return n <= 0 ? n % d : d + 1 + (n - 1) % d; 
} 

d < 0 के लिए, वहाँ एक अपरिहार्य समस्या मामला है जब d == -1 और nInteger.MIN_VALUE है, तब से गणितीय परिणाम प्रकार overflows। उस स्थिति में, उपर्युक्त फॉर्मूला लपेटा परिणाम देता है, जैसे कि सामान्य जावा डिवीजन करता है। जहां तक ​​मुझे पता है, यह एकमात्र कोने का मामला है जहां हम चुपचाप 'गलत' परिणाम प्राप्त करते हैं।

+0

@trutheality: गाह, मैं मूर्ख हूँ! धन्यवाद; इसे तुरंत ठीक कर देगा! –

+0

@trutheality: सच है, सिवाय इसके कि परिणाम अभी भी MIN_VALUE के रूप में आता है, जो गणितीय रूप से गलत है (लेकिन सही मॉड्यूलो 2 ** , तो शायद यह काफी अच्छा है)। मुझे एक बुरा लगा है कि अन्य कोने के मामले 'd <0' के लिए छिपे हुए हैं, लेकिन यह पता लगाने में समय नहीं लगा कि वे सभी क्या हैं। शायद मुझे ऐसा करना चाहिए। –

+0

हू, पता चला कि मुझे पता नहीं था कि विभाजन वास्तव में बह सकता है। – trutheality

1
return BigDecimal.valueOf(n).divide(BigDecimal.valueOf(d), RoundingMode.FLOOR).longValue();