Newsgroup: it.comp.lang.c++
Titolo: Annerire lo schermo

Come si fa annerire lo schermo? E per farlo ritornare?

Come si fa annerire lo schermo? E per farlo ritornare?
Come al solito, non ci dici nulla sul sistema che usi...!
Ovviamente, le procedure necessarie dipendono del
tutto dal sistema in questione.
Su Win32 (WinNT, Win95, Win98, WinCE, ecc), un
modo per "annerire lo schermo" e`: ottieni un device
context per l'intero schermo (con GetWindowDC(0));
dipingici su quello che vuoi (GetSystemMetrics con
parametri SM_CXFULLSCREEN, SM_CYFULLSCREEN
te ne dara` le dimensioni; con FillRect riempi il
rettangolo che vuoi dei colore che vuoi; ecc, ecc).
Per ripristinare, hai due scelte: salvati il contenuto
prima di cambiarlo (ad es con BitBlt), oppure manda
a ogni finestra top-level (EnumWindows rende assai
facile un loop su tutte le finestre top-level) una
richiesta di WM_PAINT perche` si ridipinga (anche
SendMessage(HWND_BROADCAST, ecc) ti serve
per mandare lo stesso messaggio a tutte le varie
finestre top-level, in modo piu` rapido).
Esistono sicuramente altri approcci, ma questo e` uno.
Alex

Ringrazio coloro che mi hanno consogliato di utilizzare gprof per
identificare i colli di bottiglia dei miei programmi in C++.
Ho scoperto che uno dei miei moduli piu' inefficienti calcola la
distanza tra due punti nello spazio utilizzando le cosiddette
``condizioni al contorno periodiche''.                       
In fortran cio' si realizza facilmente utilizzando la funzioni anint(x),
che dato un numero reale fornisce il numero intero che lo approssima
meglio (ad esempio, anint(0.7)=1, anint (-0.3)=0, anint (1.1)=1 e cosi'
via). 
In C++ anint(x) non esiste (almeno credo), per cui ho dovuto scriverla
io e credo di avere creato un mostricciattolo :-)
Eccola qui:
long int anint (float x)
{
 x -= floor(x);
 x=(fabs(x) >= fabs(x-1)) ? : x-1 : x;
 return x;
}
sono sicuro che si possa fare meglio di cosi' e saro' grato a chi mi
vorra' cortesemente dare una dritta.
Grazie in anticipo,
Massimo
-- 
Massimo Boninsegni
Department of Physics 
San Diego State University
http://rainbow.sdsu.edu/~massimob

 Grazie in anticipo,
double x, int i;
i = x >= 0 ? x+0.5 : x-0.5;
-- 
Maurizio Loreti                      
http://wwwcdf.pd.infn.it/~loreti/mlo.html
Un. of Padova, Dept. of Physics - Padova, Italy          
lor...@padova.infn.it

}
Sono perplesso su questa implementazione... come fa a
tornare "il numero intero che meglio approssima" x, quando
proprio la prima istruzione della funzione distrugge questa
informazione?  Ad esempio, se x e` 12.3: dopo la prima
istruzione, x resta pari a 0.3 -- hai buttato il "12", cioe`
proprio la parte intera...?
Non vorrei che fossero simili anomalie a darti poi dei
problemi su tutto l'algoritmo, piuttosto che "inefficienza"
della anint stessa.  Comunque, pensando a quella...:
Secondo me, l'implementazione in C++ portatile che ti puo`
dare le migliori prestazioni su Intel (dove immagino giri il
tuo programma in modo primario?) dovrebbe essere:
    long int anint(double x)
    {
        if(x<0)
            return x-0.5;
        else
            return x+0.5;
    }
L'argomento double e` probabilmente piu` efficiente di
uno float su piattaforme Intel; il test sul segno di x puo`
risultare piu` efficiente se fatto direttamente, piuttosto
che non attraverso fabs (se non sbaglio:
    fabs(x) >= fabs(x-1)
e` esattamente equivalente a:
    x>=0.5
e non mi e` chiaro perche` testare questo, comunque,
se va testato, farlo direttamente puo` certo essere piu`
veloce che non passare da fabs, penso).
Facci sapere...
Alex

 Alex


ancora troppo influenzato dal fortran.
"Evitare gli if" non e` una brutta regola, ma bisogna pensare che l'operatore
ternario "? :" E` un if -- non come sintassi, certo, ma sappiamo tutti che quel
che conta davvero e` la semantica, non la sintassi.
Comunque: un altro approccio da testare e` quello di basarsi su:
    double modf( double x, double *intptr );
che e` un'altra funzione standard ANSI, che torna la parte frazionaria di x
con lo stesso segno di x (e attraverso il puntatore intptr deposita anche la
parte intera idem, anche se a noi non interessa).  Se ho capito bene quel
che cerchi, puo` darsi che:
    int frazPart(double x) {
        double junk;
        double fraz = modf(x,&junk);
        if(fraz <= -0.5) return -1;
        else if(fraz >= 0.5) return 1;
        else return 0;
    }
risulti piu` veloce -- l'unica e` misurare i vari approcci sulle specifiche
piattaforme che ti interessano.  Un altro approccio, dopo la modf, e`:
        return fraz+fraz;
che puo` evitare gli if e quindi essere forse piu` veloce -- dipendera`,
pero`, dalla piattaforma, quindi, prova e misura e facci sapere...!
Alex

 0, 1, ovvero -1?
Allora, la cosa migliore sono degli esempi: 
se x=-0.49, x-anint(x)=-0.49
se x=-0.51  x-anint(x)=0.49
se x=12.49 x-anint(x)=0.49
se x=7.51 x-anint(x)=-0.49
chiaro, no :-)   ?
Comunque ho gia' provato ad utilizzare quanto suggeritomi
precedentemente ed in effetti funziona meglio. Ho apportato una serie di
altre modifiche per cui, da 8 volte piu' lento della versione fortran,
com'era all'inizio, il programma e' adesso ``solo'' 4 volte piu' lento. 
Il mio obiettivo e' quello di arrivare ad un fattore due di differenza
tra il fortran ed il C++. Arrivato a quel punto, secondo me non ha senso
inseguire l'ottimizzazione a tutti i costi visti gli altri vantaggi che
derivano dall'utilizzo del C++.
Grazie ancora per le rapide ed esaurienti risposte.


chiaro, no :-)   ?
Non ancora, perche`, ripeto, tu, dalla tua funzione, torni un int, mentre
i risultati che mostri qua sono a virgola mobile; quali di questi vuoi che
corrispondano a 0, quali a 1, quali a -1?  (immagino siano solo questi
tre i risultati che ti interessa poter ricevere dalla tua funzione?)
Alex

 Alex


> >se x=7.51 x-anint(x)=-0.49
    [snip della confusione fra double ed int]
Ok, allora, ricapitolando, tu cerchi: fra i double
tali che sottratti ad x danno un intero, quello
che ha il minimo valore assoluto.
Una funzione standard di C e C++ (che si puo`
dunque sperare sia implementata con codice
molto ben performante) e` la seguente:
    double modf( double x, double *intptr );
che ti torna la "parte frazionaria" (con segno
eguale ad x; inoltre deposita in *intptr la
relativa "parte intera", pure di egual segno,
il che non ti interessa, ma, tant'e`) -- diciamo
y questa "parte frazionaria".
Questo valore y e` gia` uno dei due "candidati"
da considerare; infatti, sottratto ad x, da` un
intero, e ha valore assoluto fra 0 e 1.  Se il
suo valore assoluto e` entro 0.5, sara` dunque
gia` il valore da ritornare; se invece y e` oltre
0.5, il valore da ritornare sara` 1.0-y, mentre,
se e` sotto -0.5, sara` da ritornare 1.0+y.
Puo` meritare di provare vari dettagli nelle
implementazioni di questo test tripartito, che,
non si sa mai, possono generare codice di
diversa efficienza, comunque la prima cosa
da provare e` la piu` semplice in assoluto:
    double numerodiboninsegni(double x) {
        double y,junk;
        y = modf(x,&junk);
        if(y>0.5) return 1.0-y;
        if(y<-0.5) return 1.0+y;
        return y;
    }
Alex