फास्ट लाइन ड्राइंग एल्गोरिथ्म


9

कार्य 16-बिट पूर्णांक की एक सरणी में क्षैतिज रेखा खींचने का एक तरीका खोजना है।

हम प्रति शब्द 16 पिक्सेल के साथ एक 256x192 पिक्सेल सरणी मान रहे हैं। एक पंक्ति सेट (1) बिट्स का एक सन्निहित रन है। लाइनें किसी भी शब्द के बीच में शुरू हो सकती हैं, किसी अन्य शब्द को ओवरलैप कर सकती हैं, और किसी भी शब्द में समाप्त हो सकती हैं; वे एक ही शब्द में शुरू और समाप्त भी हो सकते हैं। वे अगली पंक्ति में नहीं जा सकते। संकेत: बीच के शब्द आसान हैं - बस 0xffff लिखें, लेकिन किनारों को मुश्किल होगा, जैसा कि एक ही शब्द में शुरुआत और अंत के लिए मामले को संभालना होगा। एक फ़ंक्शन / प्रक्रिया / दिनचर्या को क्षैतिज शुरुआत और स्टॉप पॉइंट्स को इंगित करने के साथ-साथ एआई समन्वय का संकेत x0 और X1 समन्वय करना चाहिए।

मैं खुद को इससे बाहर करता हूं क्योंकि मैंने एक एम्बेडेड प्रोसेसर के लिए लगभग एक समान एल्गोरिथ्म डिजाइन किया है लेकिन मैं उत्सुक हूं कि अन्य लोग इसके बारे में कैसे जाएंगे। अपेक्षाकृत तेज़ संचालन का उपयोग करने के लिए बोनस अंक (उदाहरण के लिए, 64 बिट गुणा या फ्लोटिंग पॉइंट ऑपरेशन एक एम्बेडेड मशीन पर तेज़ नहीं होगा, लेकिन एक साधारण बिट शिफ्ट होगा।)


2
कोडगॉल्फ लघु कोड के बारे में है, न कि तेज कोड या गति के लिए अनुकूलन।
हॉलवाबो २ hall

@hallvabo मेरा सॉल्यूशन काफी छोटा है, लगभग 5 लाइन जब चेकिंग और अतिरिक्त फीचर्स (जैसे उन्हें सेट करने के लिए टॉगल करने वाले पिक्सल) को हटा दिया जाता है।
थॉमस ओ

9
@hallvabo, यह साइट न केवल कोडगॉल्फ है। गति के लिए अनुकूलन के बारे में भी है, लेकिन सभी प्रकार के अनुकूलन के लिए नहीं: हार्डवेयर विवरण नहीं, लेकिन एल्गोरिथ्म की जटिलता।
१२:२२

@ नाकिलोन: मैं असहमत हूं। फिर इस साइट का नाम कोड गोल्फ क्यों है? एल्गोरिथम जटिलता और गति अनुकूलन चर्चाओं के लिए हजारों अन्य साइटें हैं।
हॉलवबो

5
@hallvabo: एफएक्यू से - "कोड गोल्फ - स्टैक एक्सचेंज कोड गोल्फरों के लिए है और उन लोगों के लिए है जो कोड गोल्फिंग में रुचि रखते हैं (शुरुआती से विशेषज्ञों तक), और प्रोग्रामिंग पहेलियाँ।" मैं इसे एक प्रोग्रामिंग पहेली मानता हूं।
थॉमस ओ

जवाबों:


3

यह कोड मानता है कि x0 और X1 दोनों समावेशी एंडपॉइंट हैं, और यह शब्द थोड़ा एंडियन हैं (यानी (0,0) पिक्सेल के साथ सेट किया जा सकता है array[0][0]|=1)।

int line(word *array, int x0, int x1, int y) {
  word *line = array + (y << 4);
  word *start = line + (x0 >> 4);
  word *end = line + (x1 >> 4);
  word start_mask = (word)-1 << (x0 & 15);
  word end_mask = (unsigned word)-1 >> (15 - (x1 & 15));
  if (start == end) {
    *start |= start_mask & end_mask;
  } else {
    *start |= start_mask;
    *end |= end_mask;
    for (word *p = start + 1; p < end; p++) *p = (word)-1;
  }
}

1
कितना तेज है?
उपयोगकर्ता अज्ञात

1

अजगर

यहाँ मुख्य चाल पिक्सेल के बिटमास्क को संग्रहीत करने के लिए लुकअप टेबल का उपयोग करना है। यह कुछ ऑपरेशन बचाता है। एक 1kB तालिका इन दिनों एक एम्बेडेड प्लेटफॉर्म के लिए भी बड़ी नहीं है

यदि स्थान वास्तव में तंग है, तो & 0xf के जोड़े की कीमत के लिए लुकअप टेबल को केवल 64B तक घटाया जा सकता है

यह कोड पाइथन में है, लेकिन बिट संचालन का समर्थन करने वाली किसी भी भाषा को पोर्ट करना सरल होगा।

यदि C का उपयोग कर रहे हैं, तो आप Duff के उपकरणswitch से लूप को अनडिंड करने पर विचार कर सकते हैं । चूंकि रेखा अधिकतम 16 शब्दों की चौड़ी है, इसलिए मैं 14 रेखाओं का विस्तार करूंगा और पूरी तरह से फैलाऊंगा।switchwhile

T=[65535, 32767, 16383, 8191, 4095, 2047, 1023, 511,
   255, 127, 63, 31, 15, 7, 3, 1]*16
U=[32768, 49152, 57344, 61440, 63488, 64512, 65024, 65280,
   65408, 65472, 65504, 65520, 65528, 65532, 65534, 65535]*16

def drawline(x1,x2,y):
    y_=y<<4
    x1_=y_+(x1>>4)
    x2_=y_+(x2>>4)
    if x1_==x2_:
        buf[x1_]|=T[x1]&U[x2]
        return    
    buf[x1_]|=T[x1]
    buf[x2_]|=U[x2]        
    x1_+=+1
    while x1_<x2_:
        buf[x1_] = 0xffff
        x1_+=1


#### testing code ####

def clear():
    global buf
    buf=[0]*192*16

def render():
    for y in range(192):
        print "".join(bin(buf[(y<<4)+x])[2:].zfill(16) for x in range(16))


clear()
for y in range(0,192):
    drawline(y/2,y,y)
for x in range(10,200,6):
    drawline(x,x+2,0)
    drawline(x+3,x+5,1)
for y in range(-49,50):
    drawline(200-int((2500-y*y)**.5), 200+int((2500-y*y)**.5), y+60)
render()

1

यहाँ मेरे पायथन उत्तर का एक सी संस्करण है, जबकि लूप के बजाय स्विच स्टेटमेंट का उपयोग करके और सरणी इंडेक्स के बजाय पॉइंटर को बढ़ाकर इंडेक्सिंग को कम किया गया।

अतिरिक्त निर्देशों के एक जोड़े के लिए T [X1 & 0xf] और U [x2 & 0xf] का उपयोग करके लुकअप टेबल का आकार काफी हद तक कम किया जा सकता है

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

unsigned short T[] = {0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001,
                      0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff,
                      0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001};

unsigned short U[] = {0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff,
                      0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
                      0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff};

unsigned short buf[192*16];

void clear(){
    int i;
    for (i=0; i<192*16; i++) buf[i]==0;
}

void render(){
    int x,y;
    for (y=0; y<192; y++){
        for (x=0; x<256; x++) printf("%d", (buf[(y<<4)+(x>>4)]>>(15-(x&15)))&1);
        printf("\n");
    }
}

void drawline(int x1, int x2, int y){
    int y_ = y<<4;
    int x1_ = y_+(x1>>4);
    int x2_ = y_+(x2>>4);
    unsigned short *p = buf+x1_;

    if (x1_==x2_){
        *p|=T[x1]&U[x2];
        return;
        }

    *p++|=T[x1];
    switch (x2_-x1_){
    case 14: *p++ = 0xffff;
    case 13: *p++ = 0xffff;
    case 12: *p++ = 0xffff;
    case 11: *p++ = 0xffff;
    case 10: *p++ = 0xffff;
    case 9: *p++ = 0xffff;
    case 8: *p++ = 0xffff;
    case 7: *p++ = 0xffff;
    case 6: *p++ = 0xffff;
    case 5: *p++ = 0xffff;
    case 4: *p++ = 0xffff;
    case 3: *p++ = 0xffff;
    case 2: *p++ = 0xffff;
    case 1: *p++ = U[x2];
    }     
}


int main(){
    int x,y;
    clear();

    for (y=0; y<192; y++){
        drawline(y/2,y,y); 
    }

    for (x=10; x<200; x+=6){
        drawline(x,x+2,0);
        drawline(x+3,x+5,1);
    }

    for (y=-49; y<50; y++){
        x = sqrt(2500-y*y);
        drawline(200-x, 200+x, y+60);
    }
    render();
    return 0;
    }

कितना तेज है?
उपयोगकर्ता अज्ञात

@user अज्ञात, स्ट्रिंग का एक टुकड़ा कब तक है? मुझे लगता है कि यह स्वीकृत उत्तर की तुलना में तेज़ होना चाहिए क्योंकि यह काम की मात्रा को थोड़ा कम करने के लिए लुकअप टेबल का उपयोग करता है। आप उन्हें क्यों नहीं आज़माते हैं और हमें बताएं कि आप क्या पाते हैं?
gnibbler

1

स्केल, 7s / 1M लाइनों 4.1s / 1M लाइनों

// declaration and initialisation of an empty field: 
val field = Array.ofDim[Short] (192, 16) 

पहला कार्यान्वयन:

// util-method: set a single Bit:
def setBit (x: Int, y: Int) = 
  field (y)(x/16) = (field (y)(x/16) | (1 << (15 - (x % 16)))).toShort 
def line (x0: Int, x1: Int, y: Int) = 
  (x0 to x1) foreach (setBit (_ , y))

आंतरिक विधि कॉल को समाप्त करने के बाद, और इसके स्थान पर थोड़ी देर के लूप के साथ, मेरे 2Ghz सिंगल कोर पर स्केल 2.8 के साथ यह 1 Mio को निरस्त कर देता है। 4.1s सेकंड में लाइनें। प्रारंभिक 7 के बजाय।

  def line (x0: Int, x1: Int, y: Int) = {
    var x = x0
    while (x < x1) {  
      field (y)(x/16) = (field (y)(x/16) | (1 << (15 - (x % 16)))).toShort
      x += 1
    }
  }

टेस्टकोड और आह्वान:

// sample invocation:
line (12, 39, 3) 
// verification 
def shortprint (s: Short) = s.toBinaryString.length match {          
  case 16 => s.toBinaryString                                          
  case 32 => s.toBinaryString.substring (16)                           
  case x  => ("0000000000000000".substring (x) + s.toBinaryString)}

field (3).take (5).foreach (s=> println (shortprint (s)))            
// result:
0000000000001111
1111111111111111
1111111100000000
0000000000000000
0000000000000000

प्रदर्शन का परीक्षण:

  val r = util.Random 

  def testrow () {
    val a = r.nextInt (256)
    val b = r.nextInt (256)
    if (a < b)
      line (a, b, r.nextInt (192)) else
        line (b, a, r.nextInt (192)) 
  }

  def test (count: Int): Unit = {
    for (n <- (0 to count))
      testrow ()
  }

  // 1 mio tests
  test (1000*1000) 

यूनिक्स टूल समय के साथ परीक्षण किया गया, स्टार्टअप-टाइम, संकलित कोड, कोई जेवीएम-स्टार्ट-अप चरण सहित उपयोगकर्ता-समय की तुलना करना।

लाइनों की संख्या में वृद्धि से पता चलता है, कि हर नए मिलियन के लिए, उसे अतिरिक्त 3.3s की आवश्यकता होती है।

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