Newsgroup: it.comp.lang.c++
Titolo: Arrotondare double...

Qualcuno conosce una funzione del C++ (possibilmente del VC++ 5) che
arrotondi un valore in virgola mobile (diciamo un double)? 
Sarei disposto a realizzarmela da solo una tale funzione, però ho un
problema: vorrei evitare cast, per cui mi servirebbe una funzione che
richiedesse un double (o float) e restituisse un valore intero (magari
troncando la parte decimale). Ma io una tale funzione non l'ho
trovata! Infatti floor(double) o ceil(double) fanno esattamente queste
cose, però restituiscono ancora un double e non un valore intero!
So benissimo che per troncare la parte decimale basta scrivere:
(int)valoredouble , ma ripeto che vorrei evitare cast di qualsiasi
tipo.
GRAZIE
Daniele.

Prima di tutto per favore spiegaci perché vuoi evitare i cast, che ci
hai messo addosso una curiosità....
Se vuoi evitare di _scrivere_ il cast, ma non il suo effetto, puoi
sempre assegnare il valore double ad una variabile int, per esempio:
    int i;
    double d = 15.46;
    i = d;
Altrimenti, se devi scegliere una strada contorta, stampa su una stringa
il valore numerico double con sprintf() e poi rileggilo come intero
utilizzando sscanf(). Non ti garantisco, però, che queste funzioni non
facciano alcun casting al loro interno ;)
Spero di esserti stato di aiuto!
Ciao,
        Flavio.
--
Flavio Poletti
e-mail:   
pol...@writeme.com
web page: 
http://poletti.freeweb.org/
La libertà [americana] è lì, alla portata di tutti...
     ... come la chitarra ....
... ognuno suona come vuole ...
     ... e tutti suonano come vuole la libertà!
                                  (G. Gaber)

Spero di esserti stato di aiuto!
certo,
grazie
Daniele.

problema: vorrei evitare cast, per cui mi servirebbe una funzione che
    int double_to_int(double d) {
        return d+0.5;
    }
Personalmente, ritengo un *difetto* del C (ereditato dal C++) il
fatto che un double possa essere assegnato ad un intero (e,
quindi, anche ritornato in questo modo), ma qui ti fa comodo...!-)
Alex

uscita un valore intero. Da quello che ho capito, non esiste!
Per trasformare un tipo in un altro, QUALSIASI tipo in
QUALSIASI altro, *DEVE* necessariamente fare al suo
interno "un cast" (se conti anche quelli impliciti).
Non mi e` chiaro perche` il cast implicito ti vada bene se
avviene in una funzione ma non se avviene in un'altra.
*Credevo* di non essere secondo a nessuno nel mio
rispetto per il type-system e per la sua possibilita` di
aiutarci a trovare errori, ma evidentemente mi sbagliavo,
visto che, dal mio punto di vista, il tutto si _impernia_ sul
fatto che certi "cambiamenti di tipo" avvengono in modo
del tutto trasparente (e, come ho gia` commentato,
ritengo che avere sancito come trasparente il cambiamento
double->int sia stato a suo tempo un errore del C, ma,
questo e` il linguaggio, il C++ lo eredita, e pace).
Alex

aiutarci a trovare errori, ma evidentemente mi sbagliavo,
Quanto meno devi considerare anche me...
Paolo
-----------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
  e-mail: 
mar...@cli.di.unipi.it
 
-----------------------------------------------

 garantire la portabilita` dell'operazione.
floor, ceil e rint in math.h; forse non ti e' venuto in mente perche'
e' C e non C++ :-)
MLO@cmssun2 1 $ man floor
...
     ceil() returns the least  integral  value  greater  than  or
     equal  to  x.   This  corresponds to IEEE754 rounding toward
     positive infinity.
 
     floor() returns the greatest integral  value  less  than  or
     equal  to  x.   This  corresponds to IEEE754 rounding toward
     negative infinity.
 
     rint() rounds x  to  an  integral  value  according  to  the
     current IEEE754 rounding direction.
-- 
Maurizio Loreti                      
http://wwwcdf.pd.infn.it/~loreti/mlo.html
Un. of Padova, Dept. of Physics - Padova, Italy          
lor...@padova.infn.it

problema essendo una promozione di tipo.
Questa, invece, e` una asserzione *clamorosamente* errata.
Cosa il linguaggio scelga di considerare "promozione", e cosa
no, non ha nulla a che vedere con "assicurazioni che questo
sia corretto" ne` con garanzie di "stesso risultato su tutte le
architetture".
Quel che non stai tenendo presente, credo, e` che non c'e`
nessuna garanzia che il numero di bit nel "significando" (spesso,
erroneamente, chiamato "mantissa") di un numero in virgola
mobile, sia sufficiente per mantenere tutti i bit presenti nel
numero intero di partenza.  Il linguaggio non offre questa
garanzia fra nessuna coppia di tipi.  In pratica, i float hanno
di solito 23 bit di significando a disposizione, contro i 31 di
un int (il segno essendo a parte).  Quindi,
    float int_to_float(int i) {
        return i;
    }
    int float_to_int(float f) {
        return f;
    }
hanno *ESATTAMENTE* lo stesso, identico problema -- non
ci sono "promozioni" che tengano... nessuno dei due formati,
float e int, puo` garantire di rappresentare con precisione tutti
i numeri rappresentabili nell'altro, ne` in teoria, ne`, sulle piu`
diffuse architetture, in pratica!
"Capita" (NESSUNA garanzia da parte del linguaggio in
merito, ma, "capita") che assegnare un int a un double non
rischi perdita di precisione su nessuna architettura a mia
conoscenza; i rapporti fra long e double invece sono piu`
problematici (visto che esistono architetture, e compilatori,
su cui long ha 64 bit, quindi 63 significativi ignorando il
segno, e double ha pure 64 bit, di cui, mi pare, appena piu`
di 50 disponibili per il significando!).
La mia "preferenza" sarebbe di ricevere un warning per
ogni assegnazione "pericolosa" per la significativita`, quindi
sicuramente per tutte quelle float->int E VICEVERSA (ma
solo facoltativamente -- warning *di portabilita`* per le
assegnazioni long->double); per sopprimere i warning,
vorrei qualcosa di intermedio fra lo static_cast<> che il
linguaggio supporta (ma e` "troppo forte") e il classico
safe_cast<> che qualsiasi programmatore C++ Standard
con il minimo interesse per la type-safety si e` gia` scritto:
template<typename T1, typename T2>
inline T1 safe_cast(const T2& t2) {
    return t1;
}
Il mio ipotetico "nowarn_cast" potrei scriverlo in VC++:
template<typename T1, typename T2>
inline T1 nowarn_cast(const T2& t2) {
#pragma warning(disable: numeri da disabilitare)
    return t1;
#pragma warning(default: gli stessi numeri)
}
ma non ho modo di esprimerlo in C++ Standard (visto
che il concetto di "warning", dallo standard, non e`
gestito).
Alex

      current IEEE754 rounding direction.
Non stai tenendo conto che anche un double può avere un 'integral value' (come 7.0).
floor() e ceil() ritornano un double, mentre rint() non l'ho trovato!
Saluti a tutti.


e' C e non C++ :-)
E` anche C++, ma, gli "integral value" forniti da queste
funzioni sono dei double, NON degli int (nulla, dunque,
garantisce che possano senza perdita di precisione
essere copiati in un int), come aveva gia` notato il
primo post di questo thread.
Alex

 floor() e ceil() ritornano un double, mentre rint() non l'ho trovato!
Corretto; rint non e' Standard C, infatti (e' una estensione - POSIX?
non ho il POSIX sotto mano e non posso rispondere) - e chiedo scusa
per l'informazione errata.  floor e ceil sono richieste dallo Standard
C ANSI-ISO, e precisamente in 7.5.6.3 e 7.5.6.1 rispettivamente.
Io credo che la mia risposta sia valida; la domanda non era su come
troncare un double?  Per chi ha in seguito chiesto se esistono
funzioni standard per questo scopo, che corrispondano insomma in
funzionalita' ad un assignment da double a intero e poi ancora a
double ebbene, eccole...



[omissis]
Mea culpa.... non avevo considerato il discorso dei bit utilizzati per
la mantissa!!!!!!!!!!!
Mi ero limitato a pensare che qualsiasi intero ha una rappresentazione in base
precisa indipendentemente dalla base... non avevo considerato la finitezza
del numero di cifre prese in considerazione.....
Comunque sotto l'ipotesi di un numero compatibile di cifre significative, vale
che il valore intero e` rappresentabile anche con uno in virgola mobile (come da te
fatto notare).


fatto notare).
E cosi` pure, "sotto l'ipotesi di un numero compatibile di cifre significative",
un valore a virgola mobile che rappresenta un numero intero puo` essere
riversato in una variabile intera; ad esempio:
    int riversa(double d) {
        if(d>=0) return d+0.1;
        else return d-0.1;
    }
permette a d di variare _considerevolmente_ rispetto all'intero che dovrebbe
rappresentare, eppure recupera detto intero.  Non mi sembra "tecnologia
spaventosamente avanzata".  Il problema fondamentale e` che nessuno mi
garantisce che l'int ritornato abbia abbastanza bit per rappresentare l'intero
che il double rappresenta -- ***ESATTAMENTE COME*** nel caso:
    double asrevir(int i) {
        return i;
    }
*nessuno mi garantisce* che il double ritornato abbia abbastanza bit di
significando per rappresentare l'intero che l'int rappresenta!
L'assoluta simmetria dei problemi nei due casi e` quello che mi rende
difficile capire la totale asimmetria delle vostre preoccupazioni; e` come
se, per qualche recondita ragione psicologica, ragionaste in termini di
interi e reali "a precisione infinita" in alcuni casi, e invece in termini piu`
vicini alla realta` dei calcolatori digitali in altri casi.  Mah, sara` dovuto
al fatto che, _in pratica_ (ad esempio su Pentium), un double ha piu`
bit di significando di quanti non ne abbia un int o anche un long, e i float
(per cui il problema sarebbe evidente) sono poco usati per ragioni sia
storiche sia pratiche.  Ma se si ragiona su questi criteri psicologici e/o
pragmatici, sarebbe meglio evitare gli appelli alla "portabilita`" (verso
cosa -- ipotetiche rappresentazioni non-IEEE-standard dei reali?)...
Alex


ma e` questo secondo me il punto... una funzione di libreria facendo dei controlli
potrebbe sollevare a run time delle eccezioni. Si tratta in sostanza di ottenere
la garanzia che la conversione non alteri la correttezza della soluzione (in questo
caso potrebbe essere preferibile segnalare la cosa che fornire un risultato
potenzialmente errato).
Il punto non e` l'impossibilita` di fare la cosa, ma la comodita` di avere il problema
gia` risolto in partenza.
Per il resto non lamento alcunche`.


gia` risolto in partenza.
Ma sarebbe veramente "comodo" avere in libreria venti o piu`
funzioni che duplichino tutti gli operatori esistenti, con in piu`
la garanzia di sollevare un'eccezione all'overflow?  E fra tutte,
la meno utile sarebbe proprio quella qui richiesta, poiche` la
correttezza della conversione e` banale da controllare, rispetto
ai test "e` avvenuto un overflow?", che, per essere portabili,
possono richiedere passaggi ben piu` "sottili".
E` sicuramente, non solo piu` comodo e piu` produttivo, ma
piu` costruttivo in termini di robustezza dei programmi, il
riuso di codice gia` esistente, robusto, testato, garantito,
di quanto non possa essere replicarne la codifica.  Ma, per
fortuna, non occorre cercare _solo_ nella libreria standard
di un linguaggio, questo codice da riutilizzare proficuamente.
La "filosofia-base" che controlla la libreria standard del C++
e` un minimalismo temprato dal pragmatismo: vi si trovano,
svarioni a parte (eh si`, ci sono anche quelli!), in sostanza,
certi "nuclei minimi di funzionalita`" che offrono al programmatore,
_o a "terze parti" che producono librerie, gratuite ovvero a
pagamento_, piu` o meno i "ganci" necessari per costruire
le estensioni necessarie.
Se questa filosofia non soddisfa, ci si puo` forse trovare molto
meglio con il linguaggio Java, che ha invece una libreria
standard che pare costruita sul principio di "ma si`, va,
cacciamoci dentro anche questo, potrebbe anche fare
comodo" (curioso il contrasto: linguaggio snello e minimale,
libreria affetta da gigantismo... un po' il contrario del C++!-).
Le eccezioni in caso d'errore, e quindi la garanzia che, se
l'applicazione prosegue nel flusso normale, le operazioni
sin qua "hanno funzionato", sono pure tipiche del Java (non
a caso ho piu` volte asserito che, conoscendo a menadito
entrambi i linguaggi, un programmatore puo` essere un
20-30% piu` produttivo in Java -- _nonostante_ la triste
perdita dell'utilissima "genericita`" dei template...!).
Alex


Tanto minimalista il C++ non mi pare...
Paolo
----------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
  e-mail: 
mar...@cli.di.unipi.it
 
----------------------------------------------------

Tanto minimalista il C++ non mi pare...
"Il C++", come linguaggio, ho appena asserito, nella stessa
mia parentesi che tu citi e, come indicato dallo "smilie" che
essa include, semi-scherzosamente, e` un po` "affetto da
gigantismo" -- quello che contestualmente asserisco essere
"snelle e minimali" (nello stesso tono) sono le sue librerie
standard.  Certamente sono tali, se le confronti, come io
stavo qui facendo, con quelle del Java, che prevedono
funzionalita` standard per un'_enorme_ gamma di compiti,
dal piu` banale "elenco dei file in un dato directory" alle
socket e altri strumenti di rete, dalle interfacce utente
grafiche all'accesso ai database, e via elencando.
Nelle librerie standard del linguaggio C++, ed e` difficile
capire il perche` se non in termini di deliberate scelte di
minimalismo, non c'e`, appunto, neppure il modo di avere
una lista dei file...!
Alex