पूर्णांक मोड 10 और पूर्णांक 10 विभाजित करने का सबसे तेज़ तरीका है?


10

यदि कोई हार्डवेयर मापांक या विभाजन कार्यों का समर्थन नहीं करता है, तो सॉफ्टवेयर द्वारा मापांक / विभाजन का अनुकरण करने के लिए कई और अधिक सीपीयू चक्र लगते हैं। यदि ऑपरैंड 10 है तो क्या विभाजन और मापांक की गणना करने का कोई तेज़ तरीका है?

अपनी परियोजना में मुझे अक्सर पूर्णांक मापांक की गणना करने की आवश्यकता होती है। विशेष रूप से, मैं PIC16F पर काम कर रहा हूं और एक एलसीडी पर एक नंबर दिखाने की आवश्यकता है। समर्थन करने के लिए 4 अंक हैं, इसलिए मापांक और विभाजन फ़ंक्शन (सॉफ़्टवेयर कार्यान्वयन) में 4 कॉल हैं। अर्थात्, निम्नलिखित की तरह:

digit = number % 10;    // call to an expensive function
number /= 10;           // call to an expensive function
somehow_lit_segments();

digit = number % 10;    // call to an expensive function
number /= 10;           // call to an expensive function
somehow_lit_segments();

digit = number % 10;    // call to an expensive function
number /= 10;           // call to an expensive function
somehow_lit_segments();

digit = number % 10;    // call to an expensive function
number /= 10;           // call to an expensive function
somehow_lit_segments();

ऐसे अन्य क्षेत्र हैं जो समान कोड का उपयोग करते हैं।


कुछ दर्जन कॉल / सेकंड एक समस्या क्यों हैं? मैं परेशान नहीं होता जब तक कि परियोजना पूरी तरह कार्यात्मक और बग-मुक्त न हो।
निक टी

मैंने देखा है कि यदि मैं लगातार मुख्य व्यस्त लूप में कुछ संख्या प्रदर्शित कर रहा हूं, तो बटन की प्रतिक्रिया धीमी हो जाती है। यानी, यह पता लगाने के लिए कि एक बटन दबाया गया है, मुझे उस बटन को थोड़ी देर प्रेस करना होगा। यह तब होता है जब सिस्टम घड़ी 32768 हर्ट्ज चल रही होती है।
डोनटालो

क्या आप इंटरप्ट का उपयोग कर रहे हैं? आप 32kHz xtal का उपयोग क्यों कर रहे हैं; यदि आप तेजी से काम करते हैं और निष्क्रिय होने पर सो जाते हैं तो आमतौर पर आपको कम शक्ति प्रदर्शन मिल सकता है।
निक टी।

मैं इंटरप्ट का उपयोग कर रहा हूं। लेकिन सिर्फ प्रदर्शन को अद्यतन करने के लिए यह उच्च गति दोलन पर स्विच करने के लायक नहीं है। शक्ति के लिहाज से। मेरे प्रोजेक्ट के लिए। इसे अपने जीवन काल का लगभग 90% कम गति की घड़ी चलाना पड़ता है।
डोनोटालो

2
सामान्य रूप से, हेनरी एस। वारेन की पुस्तक हैकर डिलाइट , जूनियर, चतुर बिट-ट्विडलिंग प्रवंचना का स्रोत है। मैंने डिवीजन सुझावों की तलाश की, और इसमें 10 से विभाजित करने के लिए कुछ भी नहीं है जो नीचे दिए गए किसी भी उत्तर से बेहतर है।
RBerteig

जवाबों:


11

यहाँ बीसीडी एल्गोरिथ्म मैं किसी बाइनरी कई साल पहले इस्तेमाल किया पर एक पाया आधारित यहाँ । मैं 7 बीजी डिस्प्ले ड्राइवर के लिए एक बाहरी बीसीडी का उपयोग कर रहा था ताकि परिणाम आउटपुट के लिए सीधे पैक किए गए बीसीडी के रूप में उचित बंदरगाहों पर लिखा जा सके।

यह काफी तेज है यदि आपके पास PIC में एक हार्डवेयर गुणक है, तो मैं PIC18F97J60 का उपयोग कर रहा था। यदि आपके पास अपने PIC पर हार्डवेयर गुणक नहीं है, तो गुणन के लिए Shift + add का उपयोग करने पर विचार करें।

यह अहस्ताक्षरित 16 बिट इंट में लेता है और 5 अंकों के साथ पैक किए गए बीसीडी को लौटाता है, इसे संशोधित किया जा सकता है और 4 अंकों के लिए तेजी से बनाया जा सकता है। यह शिफ्ट + परिवर्धन का उपयोग लगभग 10 तक विभाजन करता है लेकिन सीमित इनपुट रेंज को देखते हुए यह इस उपयोग के लिए सटीक है। आप परिणाम को अलग-अलग तरीके से पैक करना चाहते हैं और साथ ही यह भी बता सकते हैं कि परिणाम का उपयोग कैसे करें।

void intToPackedBCD( uint16_t n, uint8_t *digits ) {

    uint8_t d4, d3, d2, d1, d0, q;  //d4 MSD, d0 LSD

    d1 = (n>>4)  & 0xF;
    d2 = (n>>8)  & 0xF;
    d3 = (n>>12) & 0xF;

    d0 = 6*(d3 + d2 + d1) + (n & 0xF);
    q = (d0 * 0xCD) >> 11;
    d0 = d0 - 10*q;

    d1 = q + 9*d3 + 5*d2 + d1;
    q = (d1 * 0xCD) >> 11;
    d1 = d1 - 10*q;

    d2 = q + 2*d2;
    q = (d2 * 0x1A) >> 8;
    d2 = d2 - 10*q;

    d3 = q + 4*d3;
    d4 = (d3 * 0x1A) >> 8;
    d3 = d3 - 10*d4;

    digits[0] = (d4<<4) | (d3);
    digits[1] = (d2<<4) | (d1);
    digits[2] = (d0<<4);
}

महान लिंक, धन्यवाद! यह न केवल गति का अनुकूलन करता है, बल्कि कोड आकार को भी घटाता है। मैंने आपके लिंक से "12 बिट बाइनरी से 4 ASCII दशमलव अंकों" को लागू किया है क्योंकि इसमें कोई गुणा शामिल नहीं है।
डोनटालो

8

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

10 से गुणा करने के लिए:

y = (x << 3) + (x << 1);

10 से विभाजित करना अधिक कठिन है। मुझे कई डिवीजन एल्गोरिदम का पता है। अगर मुझे सही ढंग से याद है, तो बिट शिफ्ट्स और घटाव का उपयोग करके 10 से विभाजित करने का एक तरीका है, लेकिन मुझे सटीक तरीका याद नहीं है। यदि यह सच नहीं है, तो यह एक डिवाइड एल्गोरिथ्म है जो <130 चक्र का प्रबंधन करता है । मुझे यकीन नहीं है कि आप किस माइक्रो का उपयोग कर रहे हैं, लेकिन आप इसे किसी तरह से उपयोग कर सकते हैं, भले ही आपको इसे पोर्ट करना पड़े।

संपादित करें: स्टैक ओवरफ्लो पर कोई कहता है , यदि आप थोड़ी सी त्रुटि बर्दाश्त कर सकते हैं और एक बड़ा अस्थायी रजिस्टर होगा, तो यह काम करेगा:

temp = (ms * 205) >> 11;  // 205/2048 is nearly the same as /10

मान लें कि आपके पास विभाजन और गुणन है, तो मोडुलो सरल है:

mod = x - ((x / z) * z)

6

आप बाइनरी से पैक्ड बीसीडी में डबल डैबल एल्गोरिथ्म का उपयोग किए बिना किसी भी विभाजन में परिवर्तित कर सकते हैं । यह केवल शिफ्ट का उपयोग करता है और 3 जोड़ता है

उदाहरण के लिए 243 10 = 11110011 2 को बाइनरी में बदलें

0000 0000 0000   11110011   Initialization
0000 0000 0001   11100110   Shift
0000 0000 0011   11001100   Shift
0000 0000 0111   10011000   Shift
0000 0000 1010   10011000   Add 3 to ONES, since it was 7
0000 0001 0101   00110000   Shift
0000 0001 1000   00110000   Add 3 to ONES, since it was 5
0000 0011 0000   01100000   Shift
0000 0110 0000   11000000   Shift
0000 1001 0000   11000000   Add 3 to TENS, since it was 6
0001 0010 0001   10000000   Shift
0010 0100 0011   00000000   Shift
   2    4    3
       BCD

जब कोई हार्डवेयर विभाजक उपलब्ध नहीं है, तो यह एल्गोरिथ्म बहुत कुशल है। केवल 1 से अधिक बाईं पारी का उपयोग किया जाता है, इसलिए यह तब भी तेज है जब एक बैरल शिफ्टर उपलब्ध नहीं है


4

आपके द्वारा आवश्यक अंकों की मात्रा के आधार पर आप ब्रूट फोर्स मेथड ( d- इनपुट नंबर, t- आउटपुट ASC स्ट्रिंग) का उपयोग करने में सक्षम हो सकते हैं :

t--;
if (d >= 1000) t++; *t = '0'; while (d >= 1000) { d -= 1000; *t += 1; }
if (d >= 100) t++; *t = '0'; while (d >= 100) { d -= 100; *t += 1;}
if (d >= 10) t++; *t = '0'; while (d >= 10) { d -= 10; *t += 1;}
t++; *t = '0' + d;

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


2

यह एप्लिकेशन नोट बीसीडी अंकगणित के लिए एल्गोरिदम का वर्णन करता है, जिसमें द्विआधारी से बीसीडी में रूपांतरण और इसके विपरीत है। एपनॉट एटल द्वारा है, जो एवीआर है, लेकिन वर्णित एल्गोरिदम प्रोसेसर-स्वतंत्र हैं।


1

मेरे पास एक अच्छा जवाब नहीं है, लेकिन हमारी बहन साइट स्टैक ओवरफ्लो पर विभाजन और मॉडुलो ऑप्टिमाइज़ेशन के सटीक समान विषय पर बहुत चर्चा है

क्या आपके पास लुकअप टेबल को लागू करने के लिए पर्याप्त मेमोरी है?

हैकर्स डिलाइट का इष्टतम डिवीजन एल्गोरिदम पर एक पेपर है।


नहीं, पर्याप्त मेमोरी नहीं है। मैं इसके अलावा घटाव और बिट शिफ्ट का उपयोग करना चाहता हूं।
डोनोटालो

1

क्या आपने उस मूल्य को हर समय बीसीडी के रूप में रखने पर विचार किया है (सरल विशेष "बीसीडी वृद्धि" और "बीसीडी जोड़" सबरूटीन्स का उपयोग करते हुए), बजाय उस मूल्य को द्विआधारी रूप में रखने और आवश्यकतानुसार बीसीडी में परिवर्तित करने के लिए (समझने के लिए और अधिक कठिन उपयोग करके) कन्वर्ट बाइनरी से बीसीडी "सबरूटीन) तक?

एक समय में, सभी कंप्यूटरों ने सभी डेटा को दशमलव अंकों (दस-स्थिति गियर, दो-बाहर-पांच कोड वैक्यूम ट्यूब, बीसीडी, आदि) के रूप में संग्रहीत किया था, और यह विरासत आज भी सुस्त है। (देखें क्यों वास्तविक समय घड़ी चिप्स बीसीडी का उपयोग करते हैं )।


एलसीडी पर प्रदर्शित की जाने वाली संख्या -1,999 से लेकर 1999 तक एक चर है। यह एक तापमान को इंगित करता है और बाइनरी प्रारूप में गणना की जाती है।
डोनोटलो

1

PICList पीआईसी प्रोसेसर प्रोग्रामिंग लोगों के लिए एक अद्भुत संसाधन है।

बीसीडी रूपांतरण

क्या आपने विशेष रूप से PIC16F के लिए अनुकूलित एक ऑफ-द-शेल्फ-आज़माए गए बाइनरी-टू-बीसीडी सबरूटीन का उपयोग करने पर विचार किया है?

विशेष रूप से, PICList पर लोगों ने PIC16F पर बाइनरी-टू-बीसीडी रूपांतरण का अनुकूलन करने में बहुत समय बिताया है। वे रूटीन (प्रत्येक एक विशिष्ट आकार के लिए हाथ से अनुकूलित) को "PIC माइक्रोकंटोलर रेडिक्स रूपांतरण मैथ मेथड्स" में संक्षेपित किया गया है । http://www.piclist.com/techref/microchip/math/radix/index.htm

पूर्णांक विभाजन और मॉड

PIC16F की तरह एक सीपीयू पर, एक स्थिरांक द्वारा विभाजित करने के लिए विशेष रूप से विभाजित एक सबरूटीन अक्सर एक सामान्य प्रयोजन "चर चर बी" दिनचर्या की तुलना में बहुत तेज होता है। आप अपना कॉन्स्टेंट (इस मामले में, "0.1") "कॉन्टेंट जनरेशन फ़ॉर कॉन्स्टेंट मल्टीप्लीकेशन / डिवीजन" http://www.piclist.com/techref/piclist/codegen/constdivmul.htm में देखना चाहते हैं या बाहर देख सकते हैं। http://www.piclist.com/techref/microchip/math/basic.htm के पास डिब्बाबंद दिनचर्या ।


1

8x8 हार्डवेयर को गुणा करने पर, कोई भी रूटीन का उपयोग करके मनमाने आकार के नंबर के एक डिमॉड -10 की गणना कर सकता है जो प्रक्रिया के माध्यम से 0-2559 की सीमा में 12-बिट संख्या के लिए गणना करता है:

  1. OrigH में मूल संख्या मान लें: OrigL
  2. मूल संख्या को दो से विभाजित करें और उसे TempH में संग्रहीत करें: TempL
  3. TempL के MSB * 51 को TempH के LSB * 51 में जोड़ें। वह अनुमानित भागफल है
  4. मूल्य के MSB को त्यागते हुए अनुमानित भागफल को 10 से गुणा करें।
  5. मूल संख्या के LSB से उस परिणाम के LSB को घटाएं।
  6. यदि वह मान 10 या अधिक है (अधिकतम 19 होगा), 10 घटाएँ और 1 को अनुमानित भागफल में जोड़ें

मैं एक दिव्य दिनचर्या लिखने का सुझाव दूंगा जो संख्या का एमएसबी डब्ल्यू में होगा, और एलएसबी ने एफएसआर द्वारा इंगित किया; दिनचर्या के बाद एफएसआर में भागफल को गिरावट के बाद स्टोर करना चाहिए और शेष डब्ल्यू में छोड़ देना चाहिए। 32-बिट को 10 से लंबे समय तक विभाजित करने के लिए, एक तब कुछ का उपयोग करेगा:

  मोलव ०
  lfsr 0, _number + 3; एमएसबी की ओर इशारा
  कॉल _divmod10_step
  कॉल _divmod10_step
  कॉल _divmod10_step
  कॉल _divmod10_step

एक Divmod-6 चरण बहुत समान होगा, सिवाय 85 और 6 के स्थिरांक का उपयोग करने के बजाय 51 और 10.। दोनों ही मामलों में, मुझे उम्मीद है कि divmod10_step 20 चक्र होगा (कॉल / वापसी के लिए प्लस चार) इसलिए एक छोटा divmod10 होगा लगभग 50 चक्र हो सकते हैं और एक लंबा divmod10 लगभग 100 होगा (यदि कोई विशेष-पहला कदम है, तो कुछ चक्रों को बचा सकता है)।


1

यह सबसे तेज़ नहीं हो सकता है लेकिन एक सरल तरीका है।

 a = 65535;

    l = 0;
    m = 0;
    n = 0;
    o = 0;
    p = 0;

    while (a >= 10000)
    {   a -= 10000;
        l += 1;
    }
     while (a >= 1000)
    {   a -= 1000;
        m += 1;
    }
     while (a >= 100)
    {   a -= 100;
        n += 1;
    }
     while (a >= 10)
    {   a -= 10;
        o += 1;
    }
     while (a > 0)
    {   a -= 1;
        p += 1;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.