2009-06-18 18 views
10
#define ROUND_UP(N, S) ((((N) + (S) - 1)/(S)) * (S)) 

उपर्युक्त मैक्रो के साथ, क्या कोई व्यक्ति कृपया "(एस) -1" भाग को समझने में मेरी मदद कर सकता है, वह क्यों है?round_up मैक्रो

और भी मैक्रो की तरह:

#define PAGE_ROUND_DOWN(x) (((ULONG_PTR)(x)) & (~(PAGE_SIZE-1))) 
#define PAGE_ROUND_UP(x) ((((ULONG_PTR)(x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1))) 

मुझे पता है "(~ (PAGE_SIZE -1)))" भाग पिछले पांच बिट्स को शून्य होगा, लेकिन उसके अलावा मैं कोई खबर नहीं, विशेष रूप से भूमिका '&' ऑपरेटर नाटकों।

धन्यवाद,

उत्तर

15

ROUND_UP मैक्रो काम पूरा करने के लिए पूर्णांक विभाजन पर निर्भर है। यह केवल तभी काम करेगा जब दोनों पैरामीटर पूर्णांक हों। मुझे लगता है कि N गोल करने की संख्या है और S वह अंतराल है जिस पर इसे गोल किया जाना चाहिए। यही है, ROUND_UP(12, 5) 15 वापस आना चाहिए, क्योंकि 15 12 से 12 के पहले अंतराल है।

कल्पना कीजिए कि हम इसके बजाय गोल कर रहे थे। उस मामले में, मैक्रो बस होगा:

#define ROUND_DOWN(N,S) ((N/S) * S) 

ROUND_DOWN(12,5) 10 वापसी होगी, क्योंकि पूर्णांक प्रभाग में (12/5) 2, और 2 * 5 से 10 है लेकिन हम ROUND_DOWN नहीं कर रहे हैं, हम ROUND_UP कर रहे हैं । तो हम पूर्णांक विभाजन करने से पहले, हम सटीकता खोने के बिना जितना भी कर सकते हैं उतना जोड़ना चाहते हैं। अगर हमने S जोड़ा, तो यह लगभग हर मामले में काम करेगा; ROUND_UP(11,5) बन जाएगा ((11 + 5)/5) * 5), और 16/5 पूर्णांक विभाजन में 3 है, हम 15 प्राप्त करेंगे।

समस्या तब आती है जब हम पहले से गोल किए गए नंबर को पास करते हैं एकाधिक निर्दिष्ट। ROUND_UP(10, 5) 15 लौटाएगा, और यह गलत है। तो एस जोड़ने के बजाय, हम एस -1 जोड़ते हैं। यह गारंटी देता है कि हम कभी भी "बाल्टी" को अनावश्यक रूप से कुछ नहीं दबाएंगे।

PAGE_ मैक्रोज़ को बाइनरी गणित के साथ करना है। हम दिखाएंगे कि हम सादगी के लिए 8-बिट मानों से निपट रहे हैं। आइए मान लें कि PAGE_SIZE0b00100000 है। PAGE_SIZE-1 इस प्रकार 0b00011111 है। ~(PAGE_SIZE-1) तब 0b11100000 है।

एक बाइनरी & दो बाइनरी संख्याएं लाइन करेगा और 1 को कहीं भी छोड़ देगा कि दोनों संख्याओं में 1 था।इस प्रकार, यदि x 0b01100111 था, आपरेशन इस तरह जाना होगा:

0b01100111 (x) 
& 0b11100000 (~(PAGE_SIZE-1)) 
------------ 
    0b01100000 

आप ध्यान दें हूँ कि आपरेशन वास्तव में केवल ध्यान केंद्रित किया बाहर पिछले 5 बिट्स। बस इतना ही। लेकिन यह वास्तव में उस ऑपरेशन को PAGE_SIZE के निकटतम अंतराल तक पहुंचने की आवश्यकता थी। ध्यान दें कि यह केवल काम करता है क्योंकि PAGE_SIZE वास्तव में 2 की शक्ति थी। यह कहने की तरह थोड़ा सा है कि किसी भी मनमाना दशमलव संख्या के लिए, आप पिछले दो अंकों को शून्य करके केवल निकटतम 100 तक जा सकते हैं। यह पूरी तरह से काम करता है, और वास्तव में करना आसान है, लेकिन अगर आप 76 के निकटतम एकाधिक में घूमने की कोशिश कर रहे थे तो काम नहीं करेंगे।

PAGE_ROUND_UP वही काम करता है, लेकिन यह जितना हो सके उतना जोड़ता है इसे काटने से पहले पेज। यह थोड़े तरह की है कि मैं किसी भी संख्या में 99 जोड़कर और पर अंतिम दो अंकों को शून्य करके 100 के निकटतम एकाधिक तक कैसे जा सकता हूं। (हम PAGE_SIZE-1 जोड़ते हैं, उसी कारण हमने S-1 ऊपर जोड़ा।)

आपकी वर्चुअल मेमोरी के साथ शुभकामनाएं!

4

पूर्णांक गणित का उपयोग करना, हमेशा विभाजित नीचे दौर। इसे ठीक करने के लिए, आप सबसे बड़ी संभावित संख्या जोड़ते हैं जो परिणाम को प्रभावित नहीं करेगा यदि मूल संख्या समान रूप से विभाजित थी। संख्या एस के लिए, सबसे बड़ी संभव संख्या एस -1 है।

2 की शक्ति के लिए गोल करना विशेष है, क्योंकि आप इसे थोड़ा संचालन के साथ कर सकते हैं। 2 में से एक के पास रास्ते के नीचे शून्य होगा, 4 में से एक के पास हमेशा दो बिट्स में शून्य होगा। 2 की शक्ति का द्विआधारी प्रतिनिधित्व शून्य के गुच्छा के बाद एक बिट होता है; 1 घटाना उस बिट को साफ़ करेगा, और सभी बिट्स को दाईं ओर सेट करेगा। उस मूल्य को बदलने से उन स्थानों में शून्य के साथ थोड़ा सा मुखौटा बन जाता है जिन्हें साफ़ करने की आवश्यकता होती है। & ऑपरेटर आपके मूल्य में उन बिट्स को साफ़ करेगा, इस प्रकार मान को नीचे ले जाएगा। मूल मूल्य में जोड़ने (PAGE_SIZE-1) जोड़ने की एक ही चाल इसे नीचे की बजाय गोल करने का कारण बनती है।

0

& ऐसा करता है .. ठीक है, कुछ बाइनरी संख्याएं लेते हैं।

 
(with 1000 being page size) 
PAGE_ROUND_UP(01101b)= 
01101b+1000b-1b & ~(1000b-1b) = 
01101b+111b & ~(111b) = 
01101b+111b & ...11000b = (the ... means 1's continuing for size of ULONG) 
10100b & 11000b= 
10000b 

तो, जैसा कि आप देख सकते हैं (उम्मीद) यह एक्स के लिए PAGE_SIZE जोड़ने और फिर Anding द्वारा दौर तो यह PAGE_SIZE के नीचे बिट्स सेट नहीं हैं कि बाहर रद्द

1

पेज राउंडिंग मैक्रोज़ मान

0x03FF 
0x07FF 
0x0FFF 
:

0x0400 -- 1 KiB 
0x0800 -- 2 KiB` 
0x1000 -- 4 KiB 

PAGE_SIZE - 1 का मूल्य है, इसलिए, सभी एक बिट है: `PAGE_SIZE जैसे दो की एक शक्ति है,

इसलिए, यदि पूर्णांक 16 बिट्स (32 या 64 के बजाय - यह मुझे कुछ टाइपिंग बचाता है) थे, तो ~(PAGE_SIZE-1) का मान:

0xFC00 
0xFE00 
0xF000 

आप x (यह मानते हुए असली के लिए संदिग्ध रूप से, का मान ले जब जीवन है, लेकिन प्रदर्शनी के उद्देश्यों के लिए पर्याप्त है कि ULONG_PTR एक अहस्ताक्षरित 16-बिट पूर्णांक है) तो

PAGE_SIZE   PAGE_ROUND_DN(0xBFAB) PAGE_ROUND_UP(0xBFAB) 

0x0400  --> 0xBC00     0xC000 
0x0800  --> 0xB800     0xC000 
0x1000  --> 0xB000     0xC000 

मैक्रो नीचे दौर और एक पृष्ठ आकार के निकटतम गुणज तक 0xBFAB है। PAGE_SIZE == 0x20 (या 32) यदि अंतिम पांच बिट्स केवल शून्य हो जाएंगे।

1

वर्तमान ड्राफ्ट मानक (सी 99) के आधार पर यह मैक्रो पूरी तरह से सही नहीं है, ध्यान दें कि N के नकारात्मक मानों के लिए परिणाम लगभग निश्चित रूप से गलत होगा।

सूत्र:

#define ROUND_UP(N, S) ((((N) + (S) - 1)/(S)) * (S)) 

तथ्य यह है कि पूर्णांक विभाजन गैर नकारात्मक पूर्णांक के लिए नीचे दौर और बजाय पूर्णांक बनाना यह मजबूर करने के लिए S - 1 भाग का उपयोग करता है का उपयोग करता है।

हालांकि, पूर्णांक विभाजन शून्य की ओर गोल (सी 99, धारा 6.5.5। गुणक ऑपरेटरों, आइटम 6)। नकारात्मक N के लिए, 'राउंड अप' का सही तरीका है: 'N/S', और कुछ नहीं, कुछ भी कम नहीं।

यह और भी शामिल करता है, तो S भी एक नकारात्मक मूल्य हो, लेकिन चलो भी वहाँ नहीं जाना करने के लिए अनुमति दी है हो जाता है ... (देखें: विभिन्न की एक अधिक विस्तृत चर्चा के गलत और एक या दो सही समाधान के लिए How can I ensure that a division of integers is always rounded up?)