(A% 256) a (0xFF) से भिन्न क्यों है?


145

मैंने हमेशा यह माना कि जब (a % 256)ऑप्टिमाइज़र स्वाभाविक रूप से एक कुशल बिटवाइज़ ऑपरेशन का उपयोग करेगा, जैसे कि मैंने लिखा था (a & 0xFF)

कंपाइलर एक्सप्लोरर gcc-6.2 (-O3) पर परीक्षण करते समय:

// Type your code here, or load an example.
int mod(int num) {
    return num % 256;
}

mod(int):
    mov     edx, edi
    sar     edx, 31
    shr     edx, 24
    lea     eax, [rdi+rdx]
    movzx   eax, al
    sub     eax, edx
    ret

और जब दूसरे कोड की कोशिश कर रहा हो:

// Type your code here, or load an example.
int mod(int num) {
    return num & 0xFF;
}

mod(int):
    movzx   eax, dil
    ret

लगता है जैसे मैं पूरी तरह से कुछ याद कर रहा हूँ। कोई विचार?


64
0xFF 255 नहीं 256 है।
ऋषिकेश राजे

186
@ ऋषिकेशराजे: तो? या तो %नहीं है &
usr2564301

27
@ ऋषिकेशराजे: मुझे यकीन है कि ओपी को बहुत जानकारी है। वे विभिन्न कार्यों के साथ उपयोग किए जाते हैं।
चीयर्स एंड हीथ। - अल्फ

28
ब्याज में से, आप बेहतर परिणाम प्राप्त करते हैं numहै unsigned?
बतशेबा

20
@RishikeshRaje Bitwise और 0xFF अहस्ताक्षरित पूर्णांक के लिए modulo 2 ^ 8 के बराबर है।
2501

जवाबों:


230

यह वैसा नहीं है। कोशिश करें num = -79, और आपको दोनों ऑपरेशनों से अलग-अलग परिणाम मिलेंगे। (-79) % 256 = -79, जबकि (-79) & 0xffकुछ सकारात्मक संख्या है।

उपयोग करना unsigned int, संचालन समान हैं, और कोड संभवतः समान होगा।

PS- किसी ने टिप्पणी की

उन्हें समान नहीं होना चाहिए, a % bजैसा कि परिभाषित किया गया है a - b * floor (a / b)

ऐसा नहीं है कि इसे C, C ++, ऑब्जेक्टिव-सी (यानी उन सभी भाषाओं में परिभाषित किया गया है जहां प्रश्न में कोड संकलित होगा)।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
मार्टिज़न पीटर

52

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

-1 % 256पैदावार -1और 255जो नहीं है -1 & 0xFF। इसलिए, अनुकूलन गलत होगा।

लंबा जवाब

C ++ में वह सम्मलेन है (a/b)*b + a%b == a, जो काफी स्वाभाविक लगता है। a/bहमेशा अंश वाले भाग के बिना अंकगणित परिणाम देता है (0 की ओर झुकाव)। परिणाम के रूप में, के रूप में एक a%bही संकेत है aया 0 है।

विभाजन की -1/256पैदावार 0और इसलिए उपरोक्त स्थिति ( ) को संतुष्ट करने के लिए -1%256होना चाहिए । यह स्पष्ट रूप से अलग है जो है । इसलिए, कंपाइलर आपके इच्छित तरीके का अनुकूलन नहीं कर सकता है।-1(-1%256)*256 + -1%256 == -1-1&0xFF0xFF

N4606 राज्यों के रूप में C ++ मानक [expr.mul as4] में संबंधित अनुभाग :

अभिन्न ऑपरेंड के लिए /ऑपरेटर बीजीय भाग को किसी भी आंशिक भाग के साथ छोड़ देता है; यदि भागफल a/bपरिणाम के प्रकार में प्रतिनिधित्व (a/b)*b + a%bकरने योग्य है, तो a[...] के बराबर है ।

अनुकूलन को सक्षम करना

हालांकि, प्रकारों का उपयोग करके unsigned, अनुकूलन पूरी तरह से सही होगा , उपरोक्त सम्मेलन को संतुष्ट करते हुए:

unsigned(-1)%256 == 0xFF

यह भी देखें इस

अन्य भाषाएँ

यह विभिन्न प्रोग्रामिंग भाषाओं में बहुत अलग है, जैसा कि आप विकिपीडिया पर देख सकते हैं ।


50

C ++ 11 के बाद से, नकारात्मक num % 256होने पर गैर-सकारात्मक होना चाहिए num

तो बिट पैटर्न आपके सिस्टम पर हस्ताक्षरित प्रकारों के कार्यान्वयन पर निर्भर करेगा: एक नकारात्मक पहले तर्क के लिए, परिणाम कम से कम 8 बिट्स का निष्कर्षण नहीं है।

अगर numआपके मामले में यह एक अलग बात होगी unsigned: इन दिनों मैं उम्मीद कर रहा था कि आप एक कंपाइलर को ऑप्टिमाइज़ेशन का हवाला देंगे।


6
लगभग लेकिन काफी नहीं। यदि numनकारात्मक है, तो num % 256शून्य या नकारात्मक (उर्फ गैर-सकारात्मक) है।
नायुकी

5
कौन सा आईएमओ, मानक में एक गलती है: गणितीय रूप से मोडुलो ऑपरेशन को इस मामले में विभाजक, 256 का संकेत लेना चाहिए। यह समझने के लिए कि क्यों विचार करें (-250+256)%256==6, लेकिन (-250%256)+(256%256)मानक के अनुसार होना चाहिए, "गैर-सकारात्मक", और इसलिए नहीं 6। इस तरह की सहानुभूति को तोड़ना वास्तविक जीवन के दुष्प्रभाव हैं: उदाहरण के लिए जब पूर्णांक में "जूमिंग आउट" रेंडरिंग को कंप्यूटिंग करता है तो सभी को गैर-नकारात्मक निर्देशांक होने के लिए छवि को स्थानांतरित करना पड़ता है।
माइकल

2
@Michael Modulus कभी भी जोड़-घटाव से अधिक नहीं रहा ("साहचर्य" इस संपत्ति का गलत नाम है!), भले ही आप पत्र को गणित की परिभाषा का पालन करें। उदाहरण के लिए, (128+128)%256==0लेकिन (128%256)+(128%256)==256। शायद निर्दिष्ट व्यवहार पर अच्छी आपत्ति है, लेकिन यह मेरे लिए स्पष्ट नहीं है कि यह आपके द्वारा कहा गया है।
डैनियल वैगनर

1
@ डैनियलवागनर, आप सही कह रहे हैं, बेशक, मैं "साहचर्य" से चूक गया हूं। हालाँकि, यदि कोई भाजक का चिह्न रखता है और मॉड्यूलर अंकगणित में सब कुछ गणना करता है, तो वितरण गुण रखता है; आपके उदाहरण में आपके पास होगा 256==0। कुंजी Nमोडुलो Nअंकगणित में बिल्कुल संभव मान है , जो केवल तभी संभव है जब सभी परिणाम सीमा में हों 0,...,(N-1), नहीं -(N-1),...,(N-1)
माइकल

6
@ मिचेल:% को छोड़कर कोई मॉडुलो ऑपरेटर नहीं है, यह एक शेष ऑपरेटर है।
जॉरेन

11

मुझे संकलक के तर्क में टेलीपैथिक अंतर्दृष्टि नहीं है, लेकिन %वहाँ के मामले में नकारात्मक मूल्यों (और शून्य की ओर विभाजन दौर) से निपटने की आवश्यकता है, जबकि &परिणाम हमेशा निचले 8 बिट्स के साथ होता है।

sar"अंकगणित सही बदलाव", संकेत बिट मूल्य के साथ खाली बिट्स को भरने की तरह मेरे लिए अनुदेश लगता है।


0

गणितीय रूप से बोलते हुए, मोडुलो को निम्नलिखित के रूप में परिभाषित किया गया है:

a% b = a - b * मंजिल (a / b)

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


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

@supercat गणितीय तौर पर, मंजिल है truncate। उन दोनों का प्रभाव समान है। वे एक कंप्यूटर में एक ही लागू नहीं किया जा सकता है, लेकिन वे एक ही काम करते हैं।
user64742

5
@ TheGreatDuck: वे नकारात्मक संख्याओं के लिए समान नहीं हैं। मंजिल -2.3है -3, जबकि यदि आप -2.3एक पूर्णांक को काटते हैं जो आपको मिलता है -2En.wikipedia.org/wiki/Truncation देखें । "नकारात्मक संख्या के लिए ट्रंकेशन फ्लोर फ़ंक्शन के समान दिशा में गोल नहीं होता है"। और %नकारात्मक संख्याओं का व्यवहार ठीक यही कारण है कि ओपी वर्णित व्यवहार को देख रहा है।
मार्क डिकिंसन

@MarkDickinson मुझे पूरा यकीन है कि c ++ में modulo पॉज़िटिव डिवाइज़र्स के लिए सकारात्मक मान देता है, लेकिन मैं बहस करने वाला नहीं हूं।
15:64 बजे user64742

1
@ TheGreatDuck - उदाहरण देखें: cpp.sh/3g7h (ध्यान दें कि C ++ 98 ने यह परिभाषित नहीं किया था कि दो संभावित वेरिएंट्स में से किसका उपयोग किया गया था, लेकिन यह अधिक हाल के मानकों का है, इसलिए यह संभव है कि आपने C ++ के कार्यान्वयन का उपयोग किया हो अतीत में जो इसे अलग तरह से करता था ...)
पेरियाटा ब्रीट्टा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.