[Risolto] [C++] cout: massima precisione per i double

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

[Risolto] [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Ciao a tutti.
Sto avendo un problema dovuto al fatto che cout mi tronca, nello stampare l'output, il numero di cifre di una variabile di tipo double.
Io devo mantenere un numero "elevato" di cifre dopo la virgola, ma quando il numero di cifre prima della virgola aumenta ed arriva a 5... cout non mi stampa a video le cifre dopo la virgola.
Questo troncamento per me è una catastrofe e devo risolverlo entro pochissimo tempo.
Sto guardando alcune soluzioni online, ma tutte hanno una pseudo soluzione, nel senso che impostano a qualche valore "alto" ma fissato un parametro tipo cout.precision o cose del genere.

Io vorrei capire se esiste la possibilità di far stampare tutte le cifre dopo la virgola di una variabile di tipo double.
Dal momento che non sto risolvendo e che ho una certa "urgenza" nel trovare la soluzione, mi affido al vostro aiuto :)

Oltre alla modifica della precisione di un "cout" usato nudo e crudo, mi servirebbe fare la stessa cosa sull'overload dell'opeartore << di una classe, di cui lascio un esempio di codice:

Codice: Seleziona tutto

ostream &operator<<( ostream &output, const densHandle &foo) {
	densHandle::ldVec::const_iterator it1;
	densHandle::ulVec::const_iterator it2 = ++foo.crNormVect.begin();
	for(it1=++foo.crDensAndTrapped.begin();
	    it1!=--foo.crDensAndTrapped.end();
	    ++it1) {
				cout << *it1 / *it2 << ",";
				++it2;
	} cout << *it1;
	return output;
}
Questa classe densHandle si occupa dei calcoli e della stampa a video dei valori delle densità e viene importata nel programma principale.
Non so se cambia qualcosa. Nel senso che non se l'impostazione dei parametri per la precisione nella stampa possa essere fatta direttamente nel main o vada fatta all'interno della classe.


Grazie in anticipo :ciao:
Ultima modifica di vaeVictis il lunedì 26 maggio 2014, 10:47, modificato 4 volte in totale.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
ienaplinsky
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 954
Iscrizione: giovedì 21 gennaio 2010, 9:56
Località: Napoli

Re: [C++] cout: massima precisione per i double

Messaggio da ienaplinsky »

http://stackoverflow.com/questions/5540 ... using-cout hai provato a leggere questo parlano di includere la libreria limits.h
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Ciao, grazie per l'interessamento.
È una delle discussioni che avevo letto prima di aprire questa.
Però non avevo ben compreso la parte relativa a limits.
Pertanto, prima di andare oltre con la spiegazione, nella speranza che mi aiutiate a capire, vorrei capire una cosa: con limits io vado a modificare la precisione delle variabili, giusto?

Lo chiedo perché sto ricontrollando il mio problema in modo più approfondito da dopo pranzo e temo che oltre al problema della stampa ci sia proprio un problema di arrotondamento dei numeri double.

Il problema (sintetizzando molto) è che io vado a fare la somma del prodotto di densità che si approssimano a zero per un fattore costante di normalizzazione "volumetrica".
Una volta che ho questa "sommona", devo fare la sottrazione tra la quantità ottenuta e una quantità iniziale.
Temo che l'approssimarsi a zero delle densità faccia il casino.
Sto parlando di densità di questo ordine

Codice: Seleziona tutto

5.169118306e-16,6.816398125e-16,7.732770017e-16,8.343012645e-16,8.796606109e-16,9.154360546e-16,9.448946107e-16,9.694932994e-16,9.902841012e-16,1.008130813e-15,1.023460232e-15,1.036807331e-15,1.048462823e-15,1.05845263e-15,1.06700585e-15,1.074310565e-15,1.08040537e-15,1.085461313e-15,1.089463418e-15,1.092529589e-15,1.106201985e-15
Ognuna va moltiplicata per un intero dell'ordine del migliaio (il fattore di normalizzazione)
Ne devo fare la somma.
E poi devo fare la differenza tra questa somma e un altro intero dell'ordine del migliaio.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
toro2k
Prode Principiante
Messaggi: 148
Iscrizione: lunedì 30 gennaio 2012, 12:56
Località: Savona

Re: [C++] cout: massima precisione per i double

Messaggio da toro2k »

L'header limits dichiara il template std::numeric_limits che puoi usare per conoscere qual'è la precisione massima che puoi ottenere da un double (nel tuo caso) ma non modificarla, quella è e quella rimane. Se hai bisogno di precisione nei calcoli i double NON sono certamente il tipo giusto. C'è un articolo, What Every Computer Scientist Should Know About Floating-Point Arithmetic, che spiega piuttosto dettagliatamente il perché. Non conosco granché C++ (sto imparandolo) ma credo che GMP sia una possibile soluzione.

Se vuoi sbattere contro i limiti dei numeri in virgola mobile non serve impelagarsi con conti strani, basta una sottrazione:

Codice: Seleziona tutto

#include <iostream>
int main()
{
    double a = 0.7, b = 0.3, c = 0.4;
    std::cout << a - b - c << std::endl;
}
Che compilato ed eseguito, sulla mia macchina, produce in output il valore -5.55112e-17.

Morale: l'unica cosa che puoi ottenere lavorando su cout è di modificare la precisione con cui vengono stampati in output i numeri ma non puoi fare niente riguardo all'intrinseca imprecisione cui sono soggetti i numeri in virgola mobile (float e double).
Software is meant to be soft!
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Ok, toro2k... mi hai confermato quello che temevo.
L'articolo che hai linkato... mi sa che l'avevi linkato anche in un'altra discussione perché non mi è nuovo.
I double andavano bene nel range di valori usato fino ai test fatti stamattina... devo rivedere le simulazioni usando questi GMP.

Grazie per le indicazioni.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
toro2k
Prode Principiante
Messaggi: 148
Iscrizione: lunedì 30 gennaio 2012, 12:56
Località: Savona

Re: [C++] cout: massima precisione per i double

Messaggio da toro2k »

vaeVictis ha scritto: L'articolo che hai linkato... mi sa che l'avevi linkato anche in un'altra discussione perché non mi è nuovo.
Puo` essere... tengo un bookmark a portata di mano proprio allo scopo! :)
vaeVictis ha scritto: devo rivedere le simulazioni usando questi GMP.
Occhio, GMP è l'unica libreria che conosco, per sentito dire, che implementi numeri a precisione arbitraria in C e C++, non ho idea se e quali alternative esistano. Fossi in te aspetterei il parere di qualcuno che abbia esperienza in merito, prima di impelagarti con una libreria che ti ha suggerito il primo scemo che passa! :)
Software is meant to be soft!
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Il problema "cruciale" è che questi tipi numerici non devono andare a pesare troppo sulle performance.
Vedendo la provenienza della libreria che mi hai proposto, non credo sia proprio così "accia" :)

Comunque sì, aspetto ;)
(E nel mentre faccio qualche prova preliminare)
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
M_A_W_ 1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 856
Iscrizione: venerdì 15 febbraio 2013, 3:57
Desktop: KDE
Distribuzione: SuSE
Sesso: Maschile
Località: Un luogo geometrico
Contatti:

Re: [C++] cout: massima precisione per i double

Messaggio da M_A_W_ 1968 »

vaeVictis [url=http://forum.ubuntu-it.org/viewtopic.php?p=4563673#p4563673][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto: L'articolo che hai linkato... mi sa che l'avevi linkato anche in un'altra discussione perché non mi è nuovo.
I double andavano bene nel range di valori usato fino ai test fatti stamattina... devo rivedere le simulazioni usando questi GMP.
Quell'articolo è molto spesso citato nei miei post. Quanto al tuo problema, dovrei analizzare il tuo codice e ricavarne la stabilità e l'approssimazione dei metodi numerici che usi, ma ora non ne avrei neppure il tempo. In prima approssimazione, potresti trarre vantaggio dall'uso di una bella e potente libreria per il floating point decimale IEEE 854 (gemello da poco riveduto del più famoso IEEE 754 FP binario, che però al contrario di quest'ultimo quasi tutti ignorano, incluso un vero e proprio esercito di fisici, ingegneri e affini - i quali pure effettuano computazioni ogni giorno!). Una libreria siffatta, ad esempio, è quella della Intel - che certo non abbisogna di presentazioni, ed è stata la prima ad implementare in un processore "commerciale" - beh, un "sistemino" Z9 costa quanto un posto barca a Montecarlo... - tale standard che invece COBOL e altri linguaggi "insospettabili" incorporano da sempre.
Inoltre, puoi dare un'occhiata a questo paper per capire un po' meglio quando e se conviene invece passare alla precisione arbitraria, che alla fine potrebbe non risolvere il tuo problema o rischia di pesare ingiustificatamente sulle prestazioni.
Sì, un blog ce l'ho perfino io: gli è che mi manca il tempo...

"...in una società che sembra sempre più spaventata dai problemi troppo articolati e che rigetta come un corpo estraneo ogni elemento di complessità, sapremo ancora come utilizzare il parere degli esperti?"
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Innanzi tutto, grazie ad entrambi per gli interventi e gli spunti di riflessione e risoluzione.
Approfitto della pausa di Pasqua per vedere se e cosa cambia codificando i vostri suggerimenti.

Detto questo...
Quanto al tuo problema, dovrei analizzare il tuo codice e ricavarne la stabilità e l'approssimazione dei metodi numerici che usi, ma ora non ne avrei neppure il tempo.
cerco di riassumere brevemente, perché non credo ci voglia molto ad una persona preparata come te per capire dove possa essere il problema... se il problema gli viene spiegato da una persona chiara come me :D

Il codice riguarda una simulazione che ho fatto un paio di anni fa per la tesi e a cui ogni tanto rimetto mano per fare calcoli su regimi temporali differenti.
La simulazione riguarda l'evoluzione temporale di una "matrice densità".
Per evoluzione temporale si intende che
1) al "tempo zero" la matrice viene "popolata" da valori (di tipo double) inferiori ad 1 ma maggiori di zero in tutte le sue posizioni, tranne che nell'origine, in cui si mette un altro valore (compreso tra zero e il valore uniformemente distribuito sul resto della "griglia)
2) per i tempi successivi al primo, l'evoluzione temporale comporta che il valore di densità nel sito generico al tempo (t+1) è dato dalla media delle densità che ci sono nei suoi quattro primi vicini al tempo (t), dove il "conteggio" dei primi vicini è fatto con condizioni periodiche al contorno (è quindi un "toro" e non un rettangolo); questa evoluzione inoltre vale per tutti i siti, eccetto il sito nell'origine, il cui valore rimane fisso nel tempo.
L'evoluzione, quindi, consiste nella "propagazione" del valore inserito nell'origine all'interno del reticolo su cui invece sì è distribuito un valore uniforme. Con le ovvie analogie all'equazione del calore e tutto il resto e con tutta una serie di pippe matematiche di analogie con i random walk su reticolo e compagni bella, su cui non mi dilungo in quanto inutili alla fine della comprensione del problema.

Facendo notare a margine che la griglia ha un lato intero e dispari (per via del fatto che un asse, in entrambe le direzioni, deve essere inteso come asse di simmetria), il problema presenta una "enorme" simmetria, al punto che si può concentrare l'analisi su un ottavo del reticolo... ovvero una degli otto spicchi in cui è suddiviso dai suoi assi di simmetria. Concentrando l'analisi su questo singolo spicchio, si dovrà fare attenzione alle "nuove condizioni al contorno"

Detto questo, io faccio un tot di evoluzioni della matrice densità e poi faccio il conteggio di queste densità.
Dal conteggio di questi valori double che (in pratica) si stanno man mano avviando ad essere nulli, io ricavo il numero N di particelle contenute nella griglia. La densità del singolo sito è infatti interpretabile (visto che il sito è puntiforme) con il numero di particelle che lo occupano (numero per modo di dire... in quanto frazione di intero).
Il numero di particelle, come le singole densità, sarà un double che si avvia a diventare nullo.
Facendo la differenza tra il numero di particelle iniziali (un intero dell'ordine di qualche migliaio) e questo numero di particelle libere (double e piccolo), io mi ricavo il numero di particelle "virtualmente" intrappolate (dove virtualmente va inteso nel senso che, come spiegato sopra, la densità nell'origine non varia...).

Il problema, credo, non è dato dal fatto che io sommi un numero molto grande di singoli valori double. Almeno questo lo credo perché altre osservabili che dipendono da questa somma non mi danno problemi e sono vicine ai valori previsti teoricamente.
Io credo che il problema sia legato al fatto che alla fine io faccio la differenza appena spiegata tra un numero intero elevato e un numero double piccolo... perdendomi l'approssimazione, cosa molto grave perché poi di questi numeri approssimati devo fare logaritmi e altri "cazzi e mazzi" per i quali la precisione è fondamentale.

Comprendendo che (cosa che sto facendo prima di vedere di modificare il tipo di dato) io potrei semplicemente stamparmi il numero di particelle libere e usare questo per il datafit (modificando poco i conti teorici per ottenere quantità che dipendano dal numero di particelle libere e non dal numero di particelle intrappolate).

Pertanto, da grande ignorante in materia vi lascio due domande:
1) la somma di una elevata quantità di numeri double piccoli e dello stesso ordine può dare problemi?
2) la differenza tra un numero intero elevato e un numero double piccolo, allo stesso modo, può dare problemi?

Sto approfondendo le mie conoscenze di queste problematiche anche in virtù del fatto che questo tipo di problematiche sta pian piano diventando il mio lavoro :)

Grazie in anticipo per i vostri consigli di cui farò tesoro :ciao:
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: [C++] cout: massima precisione per i double

Messaggio da Claudio_F »

vaeVictis ha scritto: 1) la somma di una elevata quantità di numeri double piccoli e dello stesso ordine può dare problemi?
Imho no, a meno che la somma ad un certo punto non arrivi ad essere ordini di grandezza superiore ai singoli numeretti, il che porta alla seconda:
2) la differenza tra un numero intero elevato e un numero double piccolo, allo stesso modo, può dare problemi?
Imho si, perché se devi rappresentare 10E300 con un numero limitato di bit, non potrai mai sommarci o sottrarci valori più piccoli del valore della cifra (bit) meno significativa.
Ultima modifica di Claudio_F il domenica 20 aprile 2014, 19:42, modificato 1 volta in totale.
:ciao:
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Bene, io ho due regimi.
Un per tempi brevi in cui la somma dei double è "grande" e una per tempi lunghi in cui la somma dei double è piccola.
Vedrò di capire per bene cosa succede, confrontando i risultati coi valori teorici che ci si aspetta.

Lascio la discussione aperta per ulteriori interventi, che sono ovviamente più che benvenuti :)
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Avatar utente
vaeVictis
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 4703
Iscrizione: venerdì 27 luglio 2012, 17:58
Desktop: Gnome
Distribuzione: Ubuntu 20.04 64bit

Re: [Risolto] [C++] cout: massima precisione per i double

Messaggio da vaeVictis »

Dopo un periodo di "prove" posso ritenere il problema risolto.
Grazie a tutti.
Pirates arrrrrrrrrrr awesome!!!
«I fear not the man who has practiced 10000 kicks once,
but I fear the man who has practiced one kick 10000 times.»
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 4 ospiti