Newsgroup: it.comp.lang.c
Titolo: shifting...

Ciao a tutti.
avrei bisogno di semplificare (per quanto sia possibile :)
questa sequenza di operazioni, in modo che dia lo stesso risultato.
Si tratta di una parte di calcolo per disegnare una bitmap,
e sono operazioni che vengono ripetute migliaia volte
all'interno di un ciclo.
buff contiene una parola di _memoria_ a 16bit unsigned.
v ritorna un valore a 8bit unsigned.
ff è una variabile temporanea a 16bit unsigned
ff = (buffx[0] << 8) | buffx[1];
v = (ff << (8-sh)) >> 8;
volevo chiedere a voi se era possibile
semplificare questa sequenza di operazioni usando i puntatori
oppure con altre tecniche avanzate.. :)
grazie, ciao.
Davide
------------------------------
l'intera routine è questa qui:
------------------------------
void _putblockA(byte sh, byte sh2, word x1, word y1, word width, word
height, char far *buffx)
{
    register int8 x, z;
    register byte m, v, p = 0x08;
    register word ff, nb, y, bb = _BytesPerLine;
    register word mem, scr, vid = _active_page+(y1*bb)+(x1/8);
    outportb(0x03CE, 0x05);
    outportb(0x03CF, 0x00);
    outportb(0x03C4, 0x02);
    outportb(0x03CE, 0x04);
    for (z=3; z>=0; z--)
    {
      outportb(0x03C5, p);
      outportb(0x03CF, z);
      scr = vid;
      for (y=height; y>=1; y--)
      {
        mem= scr;
        nb = width;
        if (sh == 0)
        {
         if (sh2 == 7)
            for (x=nb; x>=1; x--) pokeb(0xA000, mem++, *buffx++);
         else{
            nb--;
            for (x=nb; x>=1; x--) pokeb(0xA000, mem++, *buffx++);
            m = 0xff >> (sh2+1);
            pokeb(0xA000, mem, (peekb(0xA000, mem) & m) | (*buffx & ~m));
            buffx++;
         }
        }else
        {
         if (nb == 1 && sh2 >= sh) {
            m = (0xff >> sh) ^ (0xff >> (sh2+1));
            ff= (uint)*buffx;
            v = (ff << (8-sh)) >> 8;
            pokeb(0xA000, mem, (peekb(0xA000, mem) & ~m) | (v & m));
            mem++; buffx++;
         }
         else{
            m = 0xff >> sh;
            ff= (uint)*buffx;
            v = (ff << (8-sh)) >> 8;
            pokeb(0xA000, mem, (peekb(0xA000, mem) & ~m) | (v & m));
            mem++;
            nb--;
            if (sh2 != 7 && sh2 >= sh) nb--;
            for (x=nb; x>=1; x--) {
                ff = (buffx[0] << 8) | buffx[1];
                v = (ff << (8-sh)) >> 8;
                pokeb(0xA000, mem, v);
                mem++; buffx++;
            }
            if (sh2 != 7) {
               m = 0xff >> (sh2+1);
               ff = (buffx[0] << 8) | buffx[1];
               v = (ff << (8-sh)) >> 8;
               pokeb(0xA000, mem, (peekb(0xA000, mem) & m) | (v & ~m));
               if (sh2 >= sh) { mem++; buffx++;}
            }
            buffx++;
         }
        }
        scr += bb;
      }
      p >>= 1;
    }
    outportb(0x03C4, 0x02);
    outportb(0x03C5, 0x0F);
}

 v = (ff << (8-sh)) >> 8;
Non credo si possa fare piů di tanto almeno per queste 2 righe.
Comunque se sh fosse compreso tra 0 e 8 allora potresti scrivere v = ff >>
sh; se fosse compreso tra 0 e -8... lascio a te l'ottimizzazione.
Per valori diversi (piů grandi o piů piccoli) avresti sempre 0 o 255 visto
che a quanto dici v č una variabile a 8bit per cui ti puoi anche risparmiare
il calcolo.
---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (
http://www.grisoft.com
).
Version: 6.0.688 / Virus Database: 449 - Release Date: 18/05/2004

 v = (ff << (8-sh)) >> 8;
Direi che e' equivalente a questa:
v=ff >> sh;
Prova e facci sapere.
Ciao
 Max

 sh; se fosse compreso tra 0 e -8... lascio a te l'ottimizzazione.
Hai ragione.
Per Dave:
- Che valori puo' assumere sh?
- Bisogna vedere se byte e' signed o unsigned e se, visto che sh e' un
parametro, durante la chiamata puo assumere anche valori negativi.
- Se e' signed propongo un:
  if (sh>0)
    v=ff>>sh;
  else
    v=ff<<-sh;
E prima magari controlli se abs(sh)<8
Su cosa sviluppi? Turbo C? Se hai almeno la versione 3 c'e' anche
l'assembler inline che ti puo' dare una mano
Ciao
 Max


grazie a tutti.
Saluti.
Davide


grazie ancora a tutti.
faccio delle prove e vi faccio sapere.. :)
p.s.
Se volete sapere a cosa serve quella routine,
fa parte di una GUI-toolkit che ho scritto completamente in C,
prossimamente sarà capace di multitasking, interfaccia a finestre in stile
win9x..
in realtà più che una GUI è un Desktop..
e puo' girare in "emulazione" sia in ambiente Windows che in msdos.
appena la prossima versione sarà funzionante vi faccio sapere.
ooo... non vi aspettate grandi cose, è solo l'inizio.
intanto se volete, potete guardare la primissima demo che ho fatto:
http://members.xoom.virgilio.it/ailab/spock/winneros11.zip
in questa primissima versione c'è solo l'interfaccia ridotta ai minimi
termini
non completamente funzionante! manca tutto il resto che ho fatto fino ad
oggi.
La versione a cui sto lavorando è completamente rinnovata,
ho cambiato praticamente quasi tutte le funzioni xchè senza saperlo
le avevo scritte non-rientranti e col multitasking non funzionavano.
Saluti
Davide.

     v=ff<<-sh;
       ^^^^^^^^
Ovviamente il segno non ha senso per le operazioni di shift e deve essere
omesso, di regola i valori a dx degli operatori "<<" e  ">>" sono tutti
unsigned.


sei un genio! :)
ho fatto delle prove con "v = ff >> sh" al posto di "v = (ff << (8-sh)) >>
8"
e funziona esattamente nello stesso modo!?
mi sembra un po' strano perň funziona.. :)
qualche suggerimento per fare il casting correttamente?
non sono sicuro di averli fatti tutti bene..
io uso questi tipi qui:
typedef signed char    int8;    // 8bit signed
typedef signed short   int16;   //16bit signed
typedef signed long    int32;   //32bit signed
typedef unsigned char  uchar;   // 8bit unsigned
typedef unsigned short uint;    //16bit unsigned
typedef unsigned long  ulong;   //32bit unsigned
typedef unsigned char  byte;    // 8bit unsigned
typedef unsigned short word;    //16bit unsigned
typedef unsigned long  dword;   //32bit unsigned
Ciao
Davide
-------------------------------------------------------------
questa č la nuova routine revisionata in modo definitivo.. :)
-------------------------------------------------------------
void _putblockA(byte sh, byte sh2, word x1, word y1, word width, word
height, byte far *buffx)
{
    register int8 x, z;
    register byte value, plane, masks, maskd;
    register word wmem, nbyte, yy, bxlin;
    register word pmem, scr, vid;
    plane = 0x08;
    masks = 0xff >> sh;
    maskd = 0xff >> (sh2+1);
    bxlin = _BytesPerLine;
    vid   = _active_page+(y1*bxlin)+(x1/8);
    outportb(0x03CE, 0x05);
    outportb(0x03CF, 0x00);
    outportb(0x03C4, 0x02);
    outportb(0x03CE, 0x04);
    for (z=3; z>=0; z--)
    {
      outportb(0x03C5, plane);
      outportb(0x03CF, z);
      scr = vid;
      for (yy=height; yy>=1; yy--)
      {
        pmem = scr;
        nbyte= width;
        if (sh == 0)
        {
         if (sh2 == 7)
            for (x=nbyte; x>=1; x--)
                pokeb(0xA000, pmem++, *buffx++);
         else
         {
            nbyte--;
            for (x=nbyte; x>=1; x--)
                pokeb(0xA000, pmem++, *buffx++);
            value = (peekb(0xA000, pmem) & maskd) | (*buffx & ~maskd);
            pokeb(0xA000, pmem, value);
            buffx++;
         }
        }
        else
        {
         if (nbyte == 1 && sh2 >= sh) {
            wmem  = *buffx;
            value = (wmem >> sh) & (masks ^ maskd);
            value |= peekb(0xA000, pmem) & ~(masks ^ maskd);
            pokeb(0xA000, pmem, value);
            pmem++; buffx++;
         }
         else
         {
            wmem  = *buffx;
            value = (peekb(0xA000, pmem) & ~masks) | ((wmem >> sh) & masks);
            pokeb(0xA000, pmem, value);
            pmem++;
            nbyte--;
            if (sh2 != 7 && sh2 >= sh) nbyte--;
            for (x=nbyte; x>=1; x--)
            {
                wmem  = (buffx[0] << 8) | buffx[1];
                value = wmem >> sh;
                pokeb(0xA000, pmem, value);
                pmem++; buffx++;
            }
            if (sh2 != 7)
            {
               wmem  = (buffx[0] << 8) | buffx[1];
               value = (peekb(0xA000, pmem) & maskd) | ((wmem >> sh) &
~maskd);
               pokeb(0xA000, pmem, value);
               if (sh2 >= sh) {
                  pmem++; buffx++;
               }
            }
            buffx++;
         }
        }
        scr += bxlin;
      }
      plane >>= 1;
    }
    outportb(0x03C4, 0x02);
    outportb(0x03C5, 0x0F);
}

                 value = wmem >> sh;
Puoi risparmiare qualche ciclo non usando la variabile temporanea. E' pero'
possibile che questa ottimizzazione la faccia gia' l'ottimizzatore del
compilatore.
Ciao
 Max