C / C ++ / Obj-C में एक modulo (%) ऑपरेटर को कैसे कोड करें जो नकारात्मक संख्याओं को संभालता है


86

सी-व्युत्पन्न भाषाओं (एक गणितज्ञ के रूप में) के मेरे पालतू जानवरों में से एक है

(-1) % 8 // comes out as -1, and not 7

fmodf(-1,8) // fails similarly

सबसे अच्छा उपाय क्या है?

C ++ टेम्प्लेट और ऑपरेटर के ओवरलोडिंग की संभावना की अनुमति देता है, लेकिन ये दोनों ही मेरे लिए पानी की कमी वाले हैं। उदाहरण कृतज्ञता से प्राप्त।


1
मुझे नहीं लगता है कि यह आधिकारिक परिभाषा के तहत काफी ढेर "डुप्लिकेट" है stackoverflow.com/questions/828092/… । यह सच नहीं है कि इस प्रश्न के उत्तर को उस में मिलाया जा सकता है, क्योंकि यह प्रश्न केवल मापांक के बारे में पूछता है, विभाजन भी नहीं। लेकिन मुझे लगता है कि यह प्रश्न उसी के द्वारा कवर किया गया है, इसलिए यह करीब है। मेरा जवाब वहाँ पहले से ही है, FWIW।
स्टीव जेसप

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

3
@Pi ऑउरे को मॉडुलो% कहा जाता है ... यह शेष है
obataku

1
यहाँ एक और धागा है कि यह "डुप्लिकेट" है: stackoverflow.com/questions/1082917/… इस %समस्या पर संदर्भ के लिए ।
leetNightshade

यदि आप केवल दो की शक्तियों को विभाजित कर रहे हैं, तो यह उपयोग करने के लिए एक बेहतर विचार हो सकता है और:(-1) & 8 == 7
हेनरिकस वी। जूल

जवाबों:


74

सबसे पहले मैं यह नोट करना चाहूंगा कि आप इस तथ्य पर भी भरोसा नहीं कर सकते हैं कि (-1) % 8 == -1। केवल एक चीज जिस पर आप भरोसा कर सकते हैं, वह है (x / y) * y + ( x % y) == x। हालाँकि, शेष नकारात्मक है या नहीं, कार्यान्वयन-परिभाषित है

अब यहां टेम्प्लेट का उपयोग क्यों करें? Ints और longs के लिए एक अधिभार होगा।

int mod (int a, int b)
{
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

और अब आप इसे मॉड (-1,8) की तरह कह सकते हैं और यह 7 प्रतीत होगा।

संपादित करें: मुझे अपने कोड में एक बग मिला। यदि b ऋणात्मक है तो यह काम नहीं करेगा। इसलिए मुझे लगता है कि यह बेहतर है:

int mod (int a, int b)
{
   if(b < 0) //you can check for b == 0 separately and do what you want
     return -mod(-a, -b);   
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

संदर्भ: C ++ 03 पैरा 5.6 खंड 4:

बाइनरी / ऑपरेटर भागफल की पैदावार करता है, और बाइनरी% ऑपरेटर दूसरी द्वारा पहली अभिव्यक्ति के विभाजन से शेष पैदावार देता है। यदि दूसरा ऑपरेंड / या% शून्य है तो व्यवहार अपरिभाषित है; अन्यथा (a / b) * b + a% b बराबर है यदि दोनों ऑपरेंड नॉनजेनेटिव हैं तो शेष नॉनजेगेटिव हैं; यदि नहीं, तो शेष का चिह्न कार्यान्वयन-परिभाषित है


2
@ ओम: हाँ, यह सी ++ मानक में है। <उद्धरण> अभिन्न परिचालनों के लिए / ऑपरेटर बीजीय भाग को किसी भी आंशिक भाग के साथ छोड़ देता है; यदि भागफल a / b परिणाम के प्रकार में प्रस्तुत करने योग्य है, (a / b) * b +% b% a के बराबर है। </ उद्धरण>
Ben Voigt

5
-1। इसे लागू हुए 11 साल हो चुके हैं। आईएसओ 9899: 1999 ने इसे परिभाषित किया, और दुर्भाग्य से खराब परिभाषा को चुना।
आर .. गिटहब स्टॉप हेल्पिंग ICE

3
@Armen: आपने सुविधाजनक रूप से फुटनोट <उद्धरण> को हटा दिया है ... पूर्णांक विभाजन आईएसओ फोरट्रान मानक, आईएसओ / आईईसी 1539: 1991 में परिभाषित नियमों का पालन करता है, जिसमें भागफल हमेशा शून्य </ उद्धरण> की ओर गोल होता है। नया सी ++ मानक इस व्यवहार को "पसंदीदा" से अनिवार्य रूप से अपग्रेड करता है, जैसे कि फोरट्रान और सी।
बेन वोइग्ट

2
@Armen: पुरानी कल्पना टूट गई है, लेकिन टूटना साइन इशू से अलग है, और जब तक आप नए शब्द को नहीं देखते हैं, तब तक याद रखना आसान है। C ++ 03 में "यदि भागफल a / b परिणाम के प्रकार में प्रतिनिधित्व करने योग्य नहीं है" नहीं था, जो INT_MIN / -1(दो पूरक कार्यान्वयन पर) समस्याओं का कारण बनता है । पुराने अनुमान के तहत, पहचान -32768 % -1करने के लिए मूल्यांकन करना होगा -65536(जो कि 16-बिट प्रकार, yuck!) की सीमा में नहीं है।
बेन वोइगट

1
पुनः "हालांकि शेष शेष नकारात्मक है या नहीं, कार्यान्वयन-परिभाषित है।", C ++ 11 गारंटी देता है कि पूर्णांक विभाजन 0.
चीयर्स और hth की

12

यहां एक C फ़ंक्शन है जो BOTH OPERANDS के लिए सकारात्मक या नकारात्मक पूर्णांक या आंशिक मानों को संभालता है

#include <math.h>
float mod(float a, float N) {return a - N*floor(a/N);} //return in range [0, N)

यह निश्चित रूप से गणितीय दृष्टिकोण से सबसे सुरुचिपूर्ण समाधान है। हालाँकि, मुझे यकीन नहीं है कि यह पूर्णांकों को संभालने में मजबूत है। Int -> fp -> int को परिवर्तित करते समय कभी-कभी फ्लोटिंग पॉइंट एरर रेंगते हैं।

मैं इस कोड का उपयोग गैर-int s, और int के लिए एक अलग फ़ंक्शन के लिए कर रहा हूं।

नोट: एन = 0 फंसाने की जरूरत है!

परीक्षक कोड:

#include <math.h>
#include <stdio.h>

float mod(float a, float N)
{
    float ret = a - N * floor (a / N);

    printf("%f.1 mod %f.1 = %f.1 \n", a, N, ret);

    return ret;
}

int main (char* argc, char** argv)
{
    printf ("fmodf(-10.2, 2.0) = %f.1  == FAIL! \n\n", fmodf(-10.2, 2.0));

    float x;
    x = mod(10.2f, 2.0f);
    x = mod(10.2f, -2.0f);
    x = mod(-10.2f, 2.0f);
    x = mod(-10.2f, -2.0f);

    return 0;
}

(नोट: आप इसे कोडपैड से सीधे संकलित और चला सकते हैं: http://codepad.org/UOgEqAMA )

आउटपुट:

fmodf (-10.2, 2.0) = -0.20 == विफल!

10.2 मॉड 2.0 = 0.2
10.2 मॉड -2.0 = -1.8
-10.2 मॉड 2.0 = 1.8
-10.2 मॉड -2.0 = -0.2


दुर्भाग्य से, यह पूर्णांकों के साथ काम नहीं करता है। आपको उपयोग करने की अनुमति देने के लिए विभाजन से पहले उन्हें फ्लोटिंग पॉइंट में बदलना होगा floor()। इसके अलावा, जब आप फ्लोट में परिवर्तित होते हैं, तो आप सटीक रूप से ढीले हो सकते हैं: कोशिश करें (float)1000000001/3, आपको परिणामों पर आश्चर्य होगा!
cmaster -

9

मैंने अभी देखा है कि ब्रेज़ेन स्ट्रॉस्ट्रुप लेबल शेष ऑपरेटर के %रूप में है , कि मोडुलो ऑपरेटर।

मैं शर्त लगा सकता हूं कि यह एएनएसआई सी एंड सी ++ विनिर्देशों में इसका औपचारिक नाम है, और शब्दावली के दुरुपयोग में कमी आई है। क्या कोई इस तथ्य के लिए जानता है?

लेकिन अगर ऐसा है तो C का fmodf () फंक्शन (और शायद अन्य) बहुत भ्रामक है। उन्हें fremf (), आदि लेबल किया जाना चाहिए


1
C11 मानक (या सटीक होने के लिए अंतिम सार्वजनिक मसौदा ) में छह बार "मोडुलो" का उल्लेख किया गया है, लेकिन केवल विभिन्न प्रकारों के प्रतिनिधित्व के संबंध में। एक बार नहीं यह शेष ऑपरेटर ( %) के संबंध में "मोडुलो" का उल्लेख करता है ।
निस्स इंगस्ट्रोम

7

पॉजिटिव मोडुलो को खोजने का सबसे सरल सामान्य कार्य यह होगा- यह x के सकारात्मक और नकारात्मक दोनों मानों पर काम करेगा।

int modulo(int x,int N){
    return (x % N + N) %N;
}

6

पूर्णांकों के लिए यह सरल है। बस करो

(((x < 0) ? ((x % N) + N) : x) % N)

जहां मैं यह मान रहा हूं कि Nइस प्रकार के रूप में सकारात्मक और प्रतिनिधित्व करने योग्य है x। आपका पसंदीदा कंपाइलर इसे बाहर अनुकूलित करने में सक्षम होना चाहिए, जैसे कि यह कोडांतरक में सिर्फ एक मॉड ऑपरेशन में समाप्त होता है।


3
काम नहीं करता है: इसके लिए int x=-9001; unsigned int N=2000;2295 देता है, 999 नहीं।
ह्यूबर्ट करियो

1
@HubertKario शायद फिर से जाँच करें? कोई तरीका नहीं है कि कुछ modulo 2000 2295 देता है, तो आपने गलती की होगी।
sam hocevar

2
@SamHocevar: मुझे लगता है कि यहाँ समस्या अजीब सी पूर्णांक पदोन्नति नियम है। हस्ताक्षरित को बढ़ावा देने के लिए अहस्ताक्षरित और एक नकारात्मक हस्ताक्षरित पूर्णांक मूल्य को बढ़ावा देने के लिए अहस्ताक्षरित
आक्रमणों

1
मेरा मानना ​​है कि बहुत सरल (और अधिक कुशल) रूप होगा (x < 0) ? (x % N + N) : (x % N):।
क्रिस नोलेट

3

सबसे अच्छा समाधान bestfor एक गणितज्ञ पायथन का उपयोग करना है।

C ++ ऑपरेटर ओवरलोडिंग का इससे बहुत कम लेना-देना है। आप निर्मित प्रकारों के लिए ऑपरेटरों को अधिभार नहीं दे सकते। आप जो चाहते हैं, वह केवल एक फ़ंक्शन है। बेशक आप सी + + टेम्प्लेटिंग का उपयोग उस फ़ंक्शन को कोड के केवल 1 टुकड़े के साथ सभी प्रासंगिक प्रकारों को लागू करने के लिए कर सकते हैं।

मानक सी लाइब्रेरी प्रदान करता है fmodफ्लोटिंग पॉइंट प्रकारों के लिए, यदि मैं नाम सही ढंग से याद हूं, तो ।

पूर्णांकों के लिए आप एक C ++ फ़ंक्शन टेम्प्लेट को परिभाषित कर सकते हैं जो हमेशा गैर-नकारात्मक शेष (यूक्लिडियन डिवीजन के अनुरूप) के रूप में देता है ...

#include <stdlib.h>  // abs

template< class Integer >
auto mod( Integer a, Integer b )
    -> Integer
{
    Integer const r = a%b;
    return (r < 0? r + abs( b ) : r);
}

... और सिर्फ लिखने के mod(a, b)बजायa%b

यहाँ प्रकार है Integer हस्ताक्षर किए गए पूर्णांक प्रकार की आवश्यकता है।

यदि आप सामान्य गणित व्यवहार चाहते हैं जहां शेष का चिह्न भाजक के चिह्न के समान है, तो आप उदाहरण के लिए कर सकते हैं

template< class Integer >
auto floor_div( Integer const a, Integer const b )
    -> Integer
{
    bool const a_is_negative = (a < 0);
    bool const b_is_negative = (b < 0);
    bool const change_sign  = (a_is_negative != b_is_negative);

    Integer const abs_b         = abs( b );
    Integer const abs_a_plus    = abs( a ) + (change_sign? abs_b - 1 : 0);

    Integer const quot = abs_a_plus / abs_b;
    return (change_sign? -quot : quot);
}

template< class Integer >
auto floor_mod( Integer const a, Integer const b )
    -> Integer
{ return a - b*floor_div( a, b ); }

... पर एक ही बाधा के साथ Integer, कि यह एक हस्ताक्षरित प्रकार है।


¹ क्योंकि पायथन का पूर्णांक विभाजन ऋणात्मक अनंत की ओर घूमता है।


आपके कोड में वही बग है जैसा कि मेरे संपादन से पहले मेरा था। यदि b ऋणात्मक है तो क्या होगा? :)
अर्मेन सुनाईनयन

1
@Armen: धन्यवाद! लेकिन मैं बहुत आलसी हूँ बस के लिए संपादित करने के लिए ... :-)
चीयर्स और hth। - अल्फ

@ArmenTsirunyan: rपरिणाम बनाने के लिए है a= r + b*(a/b)सच। कोई फर्क नहीं पड़ता कि कैसे पूर्णांक विभाजन को लागू किया b*somethingजाता है b। यह rनकारात्मक होने पर भी एक मान्य मोड्यूलो परिणाम बनाता है। आप इसमें abs ( b) जोड़ सकते हैं और यह अभी भी एक मान्य modulo परिणाम होगा।
चीयर्स एंड हीथ। - अल्फ

2
@downvoters: यह उत्तर अभी भी सही है, जबकि चयनित "समाधान" में अब C ++ 11 में नई गारंटी के कारण गलत टिप्पणी है। यह अभी भी सही है कि एक जवाब को कम करने के लिए सुंदर विडंबना है। बिना किसी कारण के किसी को यह मान लेना चाहिए कि कम से कम 2 साहचर्य वाले व्यक्ति, लगभग पूर्ण अज्ञानता के साथ, इस प्रश्न की टिप्पणी और घुटने-झटका-साहचर्य को कम करके पढ़ते हैं। कृपया अपने पतन की व्याख्या करें।
चीयर्स एंड हीथ। - अल्फ

1
गणितीय रूप से वांछित परिणाम शेष के शून्य या भाजक (भाजक) के समान चिन्ह होने के लिए है। यदि भाजक ऋणात्मक है, तो शेष शून्य या ऋणात्मक होना चाहिए। C / C ++ कार्यान्वयन शेष रहने या लाभांश (अंश) के समान चिह्न होने के परिणामस्वरूप होता है।
rcgldr

2

ओह, मुझे इसके लिए% डिजाइन से भी नफरत है ...।

आप लाभांश को इस तरह से अहस्ताक्षरित कर सकते हैं:

unsigned int offset = (-INT_MIN) - (-INT_MIN)%divider

result = (offset + dividend) % divider

जहां ऑफ़सेट मॉड्यूल के (-INT_MIN) के करीब है, इसलिए इसे जोड़ने और घटाने से मोडुलो नहीं बदलेगा। ध्यान दें कि इसका अहस्ताक्षरित प्रकार है और परिणाम पूर्णांक होगा। दुर्भाग्य से यह सही ढंग से मूल्यों को परिवर्तित नहीं कर सकता INT_MIN ... (- ऑफसेट -1) क्योंकि वे अंकगणितीय अतिप्रवाह का कारण बनते हैं। लेकिन इस विधि में निरंतर विभाजक के साथ काम करने पर प्रति ऑपरेशन केवल एकल अतिरिक्त अंकगणित (और कोई शर्त नहीं) की सलाह है, इसलिए यह डीएसपी जैसे अनुप्रयोगों में उपयोग करने योग्य है।

विशेष मामला है, जहां विभक्त 2 एन (दो की पूर्णांक शक्ति) है, जिसके लिए साधारण अंकगणित और बिटवाइज तर्क का उपयोग करके मोडुलो की गणना की जा सकती है

dividend&(divider-1)

उदाहरण के लिए

x mod 2 = x & 1
x mod 4 = x & 3
x mod 8 = x & 7
x mod 16 = x & 15

इस फ़ंक्शन का उपयोग करके मोडुलो प्राप्त करने के लिए अधिक सामान्य और कम मुश्किल तरीका है (केवल सकारात्मक विभक्त के साथ काम करता है):

int mod(int x, int y) {
    int r = x%y;
    return r<0?r+y:r;
}

यह सिर्फ सही परिणाम है अगर यह नकारात्मक है।

इसके अलावा आप ट्रिक कर सकते हैं:

(p% q + q)% q

यह बहुत कम है लेकिन दो% का उपयोग करें जो आमतौर पर धीमी गति से होता है।


2

मेरा मानना ​​है कि इस समस्या का एक और समाधान इंट के बजाय लंबे प्रकार के चर के लिए उपयोग किया जाएगा।

मैं सिर्फ कुछ कोड पर काम कर रहा था, जहां% ऑपरेटर एक नकारात्मक मान लौटा रहा था, जिसके कारण कुछ मुद्दे थे ([0,1] पर समान यादृच्छिक चर उत्पन्न करने के लिए, आप वास्तव में नकारात्मक संख्या नहीं चाहते हैं :)), लेकिन चर को स्विच करने के बाद प्रकार लंबा, सब कुछ सुचारू रूप से चल रहा था और परिणाम उसी से मेल खाते थे जो मुझे मिल रहा था जब अजगर में एक ही कोड चल रहा था (मेरे लिए महत्वपूर्ण था क्योंकि मैं कई प्लेटफार्मों में एक ही "यादृच्छिक" संख्या उत्पन्न करने में सक्षम होना चाहता था।


2

इस Microsoft शोध पत्र पर आधारित एक पुराने प्रश्न का नया उत्तर यहां दिया जा रहा है और उसमें दिए गए संदर्भों के है।

ध्यान दें कि C11 और C ++ 11 के बाद, का शब्दार्थ शून्य (देखें ) की ओर छोटाdiv हो गया है । इसके अलावा, C ++ 11 से विभाजित के लिए , भागफल और शेष के बारे में निम्नलिखित की गारंटी देता है[expr.mul]/4DdqTrT

auto const qT = D / d;
auto const rT = D % d;
assert(D == d * qT + rT);
assert(abs(rT) < abs(d));
assert(signum(rT) == signum(D));

जहां signumमैप -1, 0, +1 पर निर्भर करता है कि इसका तर्क <, ==,> 0 से अधिक है ( इस प्रश्नोत्तर देखें) कोड कोड के लिए)।

काटे गए विभाजन के साथ, शेष का चिह्न लाभांश के संकेत के बराबर हैD , अर्थात -1 % 8 == -1। C ++ 11 एक std::divफ़ंक्शन भी प्रदान करता है जो सदस्यों के साथ एक संरचना लौटाता है quotऔरrem काटे गए विभाजन के अनुसार ।

कुछ अन्य परिभाषाओं, तथाकथित जैसे हैं फर्श विभाजन निर्मित छोटा कर दिया विभाजन के संदर्भ में परिभाषित किया जा सकता है

auto const I = signum(rT) == -signum(d) ? 1 : 0;
auto const qF = qT - I;
auto const rF = rT + I * d;
assert(D == d * qF + rF);
assert(abs(rF) < abs(d));
assert(signum(rF) == signum(d));

फ्लोर्ड विभाजन के साथ, शेष का चिह्न भाजक के संकेत के बराबर होता हैd । हास्केल और ओबेरॉन जैसी भाषाओं में, फ़्लोरवर्ड डिवीज़न के लिए बिलिन ऑपरेटर हैं। C ++ में, आपको उपरोक्त परिभाषाओं का उपयोग करके एक फ़ंक्शन लिखना होगा।

फिर भी एक और तरीका यूक्लिडियन डिवीजन है , जिसे बिलिन ट्रंकेटेड डिवीजन के संदर्भ में भी परिभाषित किया जा सकता है

auto const I = rT >= 0 ? 0 : (d > 0 ? 1 : -1);
auto const qE = qT - I;
auto const rE = rT + I * d;
assert(D == d * qE + rE);
assert(abs(rE) < abs(d));
assert(signum(rE) != -1);

यूक्लिडियन विभाजन के साथ, शेष का संकेत हमेशा सकारात्मक होता है


2

एक समाधान के लिए जिसमें कोई शाखाएं और केवल 1 मॉड का उपयोग नहीं किया गया है, आप निम्न कार्य कर सकते हैं

// Works for other sizes too,
// assuming you change 63 to the appropriate value
int64_t mod(int64_t x, int64_t div) {
  return (x % div) + (((x >> 63) ^ (div >> 63)) & div);
}

1
/ * चेतावनी: मैक्रो मॉड कई बार अपने तर्कों के दुष्प्रभावों का मूल्यांकन करता है। * /
#define mod (r, m) (((r)% (m)) + ((r) <0)? (m): 0)?

... या समतुल्य वर्ग के लिए कोई प्रतिनिधि प्राप्त करने की आदत डालें।


2
"समतुल्य वर्ग के लिए कोई प्रतिनिधि प्राप्त करने की आदत डालें"! यह बकवास है। यदि आप चाहते थे कि आप मूल "प्रतिनिधि" का उपयोग कर सकें r%ऑपरेटर तुल्यता कक्षाओं के साथ कोई संबंध नहीं है। यह शेष संचालक है और शेष को बीजगणितीय रूप से अशाब्दिक और विभाजक से कम होने के लिए परिभाषित किया गया है। अफसोस की बात है कि सी ने इसे गलत तरीके से परिभाषित किया। फिर भी, सबसे अच्छे उत्तरों में से एक होने के लिए +1।
आर .. गिटहब स्टॉप हेल्पिंग ICE

0

C ++ के लिए उदाहरण टेम्पलेट

template< class T >
T mod( T a, T b )
{
    T const r = a%b;
    return ((r!=0)&&((r^b)<0) ? r + b : r);
}

इस टेम्पलेट के साथ, शेष शेष शून्य होगा या विभाजक (भाजक) (ऋणात्मक अनंत की ओर गोलाई के बराबर) के समान चिन्ह होगा, शेष शेष के C ++ व्यवहार के बजाय या लाभांश के समान चिन्ह होने पर ( अंश) (शून्य की ओर गोलाई के बराबर)।


-1
define  MOD(a, b)       ((((a)%(b))+(b))%(b))

यह काम करता है लेकिन इसे मैक्रो के रूप में परिभाषित करता है जैसे कि यह नरक के रूप में बदसूरत है। यहाँ एक
टेम्पर्ड


-1

यह समाधान (उपयोग के लिए जब modसकारात्मक है) नकारात्मक विभाजन या शेष संचालन को एक साथ लेने से बचता है:

int core_modulus(int val, int mod)
{
    if(val>=0)
        return val % mod;
    else
        return val + mod * ((mod - val - 1)/mod);
}

-2

मुझे क्या करना होगा:

((-1)+8) % 8 

यह बाद वाले नंबर को वांछित के रूप में 7 देने वाले मोडुलो को करने से पहले पहले जोड़ता है। यह किसी भी संख्या में -8 के लिए काम करना चाहिए। के लिए -9 जोड़ 2 * 8।


2
और एक चर के लिए जिसका मूल्य हो सकता है -99999?
कीथ थॉम्पसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.