Newsgroup: it.comp.lang.visual-basic
Titolo: [?] Big endian... e arrotondamenti

Ciao a tutti!
Avrei bisogno di un paio di consigli per ottenere 2 algoritmi il più veloci
possibile...
1 serve per trasformare un long da "big endian" a "little endian" (il long é
scritto in big endian in un file e viene letto pari-pari come se fosse un
little endian e poi trasformato con la sub seguente, ma se ritenete più
veloce leggerlo diversamente accetto consigli...);
l'altra invece riceve un double e dovrebbe fare un arrotondamento alla terza
cifra decimale (io tronco, ma sarebbe meglio arrotondare)...
Se avete suggerimenti saranno MOLTO ben accetti...
Public Sub BigLong(LittleLong As Long)
   'Ordine di riporto:DCAB
    TmpLng1 = LittleLong And &HFFFF& 'AB
    TmpLng2 = LittleLong And &HFF0000 'C
    TmpLng3 = LittleLong And &HFF000000 'D
    If TmpLng1 And &H8000& Then
      LittleLong = TmpLng3 / &H1000000 Or TmpLng2 / &H100 Or (TmpLng1 And
&H8FFF) * &H10000 Or &H80000000
    Else
      LittleLong = TmpLng3 / &H1000000 Or TmpLng2 / &H100 Or TmpLng1 *
&H10000
    End If
End Sub
Public Sub Arrotonda(dbl As Double)
    dbl = Fix(dbl * 1000) / 1000
End Sub
                    Ciaooo ;)
                                    Allanon

 possibile...
Io mi sono fatto una DLL in C.
Non so nemmeno io se è il metodo migliore, anche perchè di C non ne so
molto.
Non so nemmeno se ne valga la pena convertirla in VB:
extern "C" __declspec(dllexport) void WINAPI BufferRev(UCHAR *b, long len)
{
    UCHAR *c = (UCHAR *) malloc(len);
    for (register int i = 0; i < len; i++)
    {
        c[len - i - 1] = b[i];
    }
    memmove(b, c, len);
    free(c);
}
In VB dovrebbe assomigliare a questo:
Sub BufferRev(b() as byte, long len)
    dim c()  as byte
    dim i    as long
    Redim c(0 to len - 1)
    for i = 0 to len - 1
        c(len - i - 1) = b(i);
    next i
    Call CopyMemory(b(0), c(0), len)
End Sub

Scusa me se ho capito la domanda devi invertire il byte alto con il byte
basso di una word (2-byte). Passandola come long sei sicuro di non avere il
segno, quindi il codice dovrebbe essere tipo:
Function ToLittleEndian(BigEndian as long) as long
  dim ByteAlto as integer
  dim ByteBasso as integer
  ByteAlto = BigEndian \ 256   'frazione con interi... equivale a shift >> 8
in C
  ByteBasso = BigEndian and 255
  ToLittleEndian = ByteBasso * 256 + ByteAlto 'Inverto l'ordine
End Function
che chiami con Little = ToLittleEndian ( &HABCD )
ed ottieni Little = &HCDAB.
Per l'arrotondamento (anzi troncamento) la prima cosa che mi viene in mente
č analoga a quella che hai fatto tu, in generale:
Function Arrotonda(dbl as double, digit as integer) as double
  Arrotonda =Fix (dbl * 10^digit)/(10^digit)
End Function
cosě chiami ValoreArrotondato = Arrotonda(10.123456,3)
Su questa macchina non ho VB quindi non posso provare se funziona quello che
ti ho scritto, comunque ti consiglio di provare Int o CInt al posto di Fix
per vedere se ti arrotondano (uno dei due o tutti e due lo fanno, ma a
memoria non me lo ricordo) o al limite lasci Fix ma gli dai (dbl * 10^digit
+ sgn(dbl)*0.5).
Ciao,
Valerio

Riguardo little endian e big endian, non so nemmemo di che cosa tu parli... ;-)
invece per quanto riguarda L'arrotondamento alla 3a cifra prova questo:
Public Sub Arrotonda(dbl As Double)
    dbl = Format(dbl, "0.###")
End Sub
Ciao
 
   § Roby §

 + sgn(dbl)*0.5).
CInt arrotonda...
Int é come Fix...
Il problema é che sto trattando coordinate geografiche espresse in metri
quindi sia CInt che Clng rischiano di limitarmi rispetto ad un double...
Pensavo allora ad un currency ed in effetti forse sarebbe la cosa migliore,
ma... é very very fuckin' slowly (maledettamente LENTO!)
Boh, ti ringrazio comunque... ;)
                    Ciao
                                            Allanon

>é very very fuckin' slowly (maledettamente LENTO!)
Ritiro tutto...
Fix é MOOOLTO LENTO e Currency é velocissimo!
            Ciao
                                    Allanon

 End Sub
10 000 000 di passaggi in 6.81 secondi, ma arrotonda!
A velocità scelgo la seconda, ma visto che la 2a arrotonda e non tronca alla
fine la differenza é poca e scelgo la 3a! ;)

 }
Ciao.
--
BSD is for UNIX-lovers -- linux is for Windows-haters.

 > }
la butto lě:
BufferRev(UCHAR *b, long len)
{UCHAR cTemp
 for(register int iI=0;iI<len/2;iI++)
   { cTemp = b[len-iI];
      b[len -iI] = b[iI];
      b[iI]=cTemp;
   }
}
hth
Alfonso

> Io mi sono fatto una DLL in C.
HPL> Un compilatore C non ti compilerebbe mai il codice che hai scritto,
HPL> perché è C++ e non C.
Io  penso che  sia codice  C che  si deve  addattare al  fatto  che e`
compilato col VC++ e deve andare in una DLL.
Fuori da Windows dubito che lo compili anche un compilatore C++...
L'uso  della chiamata a  std::reverse() e`  interessante, ma  forse si
puo` andare un  pelo piu` veloci, visto che la  dimensione del dato e`
fissa con una espressione tipo
	b = ( ( b & 0xFFFF ) << 16 ) |
	    ( ( b & 0xFF000000 ) >> 24) |
	    ( ( b & 0xFF0000) >> 8)  ;
che e` in pratica e` un loop srotolato senza test e salti.
E se si passa al C o al C++ tanto vale usare l'I/O di quei linguaggi e
fare una  funzione che  preleva un  long dal file  e lor  ritorna gia`
convertito in little endian.
HPL> BSD is for UNIX-lovers -- linux is for Windows-haters.
Hmmm...   Accademica.    Chi  e`   stato  colpito  dallo   Unix  virus
difficilmente apprezza Windows. Una cosa e` farsi capire a parole, una
cosa farsi capire a gesti.
-- 
Gian  | main(){printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Uberto|                        David Korn, 1987 ioccc best one liner 
Lauri |-------------------------------------------------------------------
(aka saint) >>Vedere X-Nospam nell'header - See X-Nospam field in Header<<

 }
Prima regola del programmatore: non reinventare ogni volta la ruota.
Il C++ ci fornisce già un algoritmo ottimo, persino (per quanto non
ce ne sia neppure bisogno) più efficiente di quelli che possiamo
scrivere noi; tutto sta nell'usarlo...


 long dal file  e lor  ritorna gia` convertito in little endian.
Certo, io scrivo *tutto* il core del programma in C++, e riservo al
VB solo la parte dell'interfaccia grafica.
Ciao.
--


> ma forse si puo` andare un  pelo piu` veloci
HPL> Stiamo parlando di tempi (misurati sul mio PC) di 2 milionesimi di
HPL> secondo per la conversione, non credo ci siano problemi di
HPL> prestazioni.
Dipende. La chiamata a funzione  dentro una DLL e` sempre una chiamata
a una funzione in un'altra pagina  di swap che non e` garantito sia in
memoria  in quel  momento. Poi  c'e`  il fatto  che std::reverse()  e`
generica come  dimensione dell'argomento e  questo da una parte  e` un
vantaggio, dall'altra  pero` inserisce dei decrementi, dei  test e dei
salti  condizionati:  istruzioni  in   piu`  e  qualche  stallo  della
pipeline. Forse, ripeto  forse, la taglia del problema  e` tale che il
vantaggio minimo guadagnato alla fine  si sente. Oppure per le CPU con
l'instruction  set dei  pentium l'espressione  che ho  scritto  non si
compila in un  codice piu` veloce (con altre  sono convinto che invece
si abbia un  miglioramento nelle prestazioni). E' indubbio  che per la
maggior parte delle  taglie dei problemi la routine  di libreria e` la
scelta migliore.  Ma avevano  chiesto la piu`  veloce e non  ho saputo
resistere :)


 > }
ummmh, questa non la sapevo.
Provvedo subito, grazie :)
pensa che non so nemmeno che differenza c'è tra C e C++ :(
Ciao

 e C++ :(
Questa però è grave ;-)


 resistere :)
Oltretutto non avevo neppure letto il problema originale, e mi ero
soffermato solo sulla funzione che invertiva un array.
Effettivamente il problema originale si poteva risolvere in altre
maniere.


 scrivere noi; tutto sta nell'usarlo...
Quale? che algoritmo usa std::reverse? Tanto per curiosità...
ciao
Alfonso.Newton

> scrivere noi; tutto sta nell'usarlo...
AM> Quale? che algoritmo usa std::reverse? Tanto per curiosità...
Non  lo ho  sottocchio,  ma  un algoritmo  ottimo  per movimentare  la
memoria deve  fare un numero minimo  di accessi tenendo  gli stessi il
piu` ravvicinati possibile al fine  di evitare al massimo swap e cache
miss e facendoli nell'ordine che fa fare meno "lavoro" alla macchina.
Spesso, per  fare algoritmi portabili  si deve scegliere  un algoritmo
molto  buono   ovunque  ma  ottimo   da  nessuna  parte   oppure  fare
un'implementazione specifica  per una certa  architettura ma terribile
in un'altra.
Cosi`  e`   successo  che  quella   che  credo  sia  la   piu`  veloce
implementazione della FFT (FFTW, 
www.fftw.org
 se non ricordo male) usi
una  tecnica particolare in  cui una  prima analisi  trova il  modo di
risolvere il problema per la  taglia data su una certa macchina, salva
il   risultato   dell'analisi   e   poi  procede   ad   applicare   il
risultato.  L'overhead  iniziale   viene  abbondantemente  ripagato  a
posteriori.


> momento.
HPL> Certo, ma questo indipendentemente da come sia implementata la
HPL> funzione.
Se d'altro canto usi una tua funzione, col C++ puoi dire che e` inline.
Ovvero comoda per l'uomo e comoda per la macchina.
HPL> BSD is for UNIX-lovers -- linux is for Windows-haters.
Cercati il  Lion's Book  (John Lion's commentary  on Unix  6th Edition
with source  code) e  dagli un'occhiata. Lo  trovi sul sito  della RTC
books. Sempre che tu non sia un fortunato possessore delle fotocopie.


 Quale? che algoritmo usa std::reverse? Tanto per curiosità...
std::reverse è un template ed utilizza iteratori, per essere un
algoritmo generico utilizzabile con diversi tipi di contenitori,
comunque questo è un equivalente scritto da me e semplificato (anche
se il codice originale è poco più complesso):
template<class T> inline void Swap(T& x, T& y)
{
    T tmp = x;
    x = y;
    y = tmp;
}
template<class T> inline Reverse(T* first, T* last)
{
    for(; first < last; ++first)
    {
        Swap(*first, *(--last));
    }
}
void BufferRev(unsigned char* b, long len)
{
    Reverse(b, b + len);


 fotocopie.
No, non lo sono.
Ciao.
--


 guadagni in prestazioni puo` essere utile.
Tralasciando il fatto che la funzione in questione (non
std::reverse, ma l'intera BufferRev) è molto più generica di quello
che serve effettivamente, per 10.000 conversioni non vale ancora la
pena di pensare a qualcosa di diverso. Sul mio PC per 10.000.000
(dieci milioni) di conversioni sono richiesti pochi decimi di
secondo.


         std::reverse(b, b + len);
Vediamo se mi puoi dare delle dritte:
Uso come compilatore c il C++Builder standard (quello che danno via con i
giornali).
Tutto ok con le righe da te segnalate, ma documentazione acclusa zero.
Dove posso trovare info sulle funz. della famiglia "std"?
Ciao

> guadagni in prestazioni puo` essere utile.
HPL> Sul mio PC per 10.000.000
HPL> (dieci milioni) di conversioni sono richiesti pochi decimi di
HPL> secondo.
Io ho fatto  un programmino di test un po'  rozzo ed effettivamente ci
si mette pochi  decimi di secondo. Pero` scrivere  codice che ci mette
molto meno diverte  :) :) (a seconda delle  macchine e del compilatore
da poco meno di meta` tempo ad un quinto :) :) ).
Non sempre  ne vale la pena  effettivamente, anzi quasi  mai per scopi
pratici usuali. Pero` diverte :) :)


 Dove posso trovare info sulle funz. della famiglia "std"?
Qui trovi una piccola introduzione alla libreria standard:
http://www.programmazione.it/index.php?entity=earticle&idArticle=567
&idArea=4
Qui trovi la documentazione della Dinkumware (che sviluppa
l'implementazione della libreria standard fornita con VC++, che è
una delle migliori):
http://www.dinkumware.com/htm_cpl/index.html
Se avessi qualcosa da chiedermi contattami pure via e-mail
(hDOTpDOTlDOTmailATsoftsharkDOTcom).


 quasi  mai per scopi pratici usuali. Pero` diverte :) :)
Non è solo divertente, è anche utille decisamente per imparare (non
si finisce mai di imparare).
Diventa inutile (anzi dannoso) solo quando si esula da scopi
didattici.


> quasi  mai per scopi pratici usuali. Pero` diverte :) :)
HPL> Non è solo divertente, è anche utille decisamente per imparare (non
HPL> si finisce mai di imparare).
HPL> Diventa inutile (anzi dannoso) solo quando si esula da scopi
HPL> didattici.
Ni.
In  un programma gestionale  una scrittura  come la  mia non  e` utile
perche' rende il  codice meno leggibile con un  guadagno effettivo che
non porta  utilita` a  nessuno. In questi  casi metterci 13  decimi di
secondo  invece  che  62  -nel  caso  piu`  favorevole  alla  libreria
standard- non interessa a nessuno.
In altri  contesti dipende.  Sicurametne  in quelli in cui  ogni ciclo
macchina conta (i.e. macchine il cui costo di esercizio e` ancora alto
- ambienti in cui purtroppo non bazzico piu`) la cosa ha invece senso,
in  quanto le  prestazioni vengono  prima della  manutenibilita`  e si
tagliano fuori le persone non in grado di mantenere certo codice.


 }
Ti faccio notare che l'algoritmo č perfettamente identico al mio (giuro che
non ho copiato:) ) , anche se quello delle Stl č meglio perchč non fa la
divisione. D'accordo che nella pratica serve molto raramente, ma insegna
delle cose, che, mutatis mutandis, si posssono utilizzare anche nei
gestionali piů biechi. E comunque a me č capitato di diver scrivere
programmi (ovviamente in C) dove addirittura dovevo posporre il confronto
delle stringhe perchč se no mi scattava il timeout. Mai dire mai...
Ciao
Alfonso

 divisione.
Non è quello il motivo per cui è meglio. Il tuo algoritmo è ottimo
(potrebbe essere più veloce di std::reverse), ma la funzione si può
fare meglio (come fa la libreria standard):
grazie a template, a funzioni inline ed agli iteratori (che io ho
per semplicità "trasformato" in puntatori) si può dividere il codice
in più funzioni (mantenendo la stessa efficienza) e rendere
l'algoritmo più leggibile ed utilizzabile molto più generalmente,
non solo con array "C" di un certo tipo (anche se al momento era
questo che ci serviva), ma anche con altri tipi di contenitori (a
patto che abbiano iteratori ad accesso casuale o bidirezionali).


 in cui  ogni ciclo macchina conta
Certo... intendevo dire che č inutile e dannoso farlo se *non* vi
sono problemi di prestazioni.
