Come posso 'tagliare' un C # doppia per il valore che verrà memorizzato come in un database SQLite?

StackOverflow https://stackoverflow.com/questions/4200736

Domanda

Ho notato che quando memorizzare un valore doppio come ad esempio x = 0.56657011973046234 in un database SQLite, e quindi recuperare in un secondo momento, ho y = 0.56657011973046201. Secondo il SQLite spec e la . NET spec (nessuno dei quali ho inizialmente preso la briga di leggere :) questo è previsto e normale.

Il mio problema è che, mentre ad alta precisione non è importante, le mie offerte app con gli utenti inserendo / selezionando doppie che rappresentano informazioni 3D di base, e quindi l'esecuzione di simulazioni su di loro per trovare un risultato. E questo ingresso può essere salvato in un database SQLite essere ricaricato e rieseguire tardi.

La confusione si verifica perché una serie appena creato di ingressi ovviamente simulare in modo leggermente diverso a quegli stessi ingressi volta memorizzati e ricaricati (come valori doppi sono cambiati). Questo è logico, ma non desiderabile.

Non ho abbastanza venire a termini di come trattare con questo, ma nel frattempo mi piacerebbe limite / bloccare gli input dell'utente a valori che possono essere esattamente memorizzati in un database SQLite. Quindi, se un input dell'utente 0.56657011973046234, è in realtà trasformato in 0.56657011973046201.

Tuttavia non sono stato in grado di capire, dato un numero, quale valore viene memorizzato nel database, corto di effettivamente memorizzare e recuperare dal database, che sembra goffa. C'è un modo stabilito di fare questo?

È stato utile?

Soluzione

doppio turno ha un'implementazione con un parametro che specifica il numero di cifre. Usare questo per turno a 14 cifre (diciamo) con: rval = Math.round (Val, 14)

Poi, intorno quando si riceve il valore dal database, e all'inizio di simulazioni, per esempio. Così i valori corrispondono?

Per ulteriori dettagli:

http://msdn.microsoft.com/en-us/library/ 75ks3aby.aspx

Un altro pensiero se non si stanno confrontando i valori nel database, solo la loro memorizzazione: Perché non semplicemente memorizzarle come dati binari? Poi tutti i bit saranno memorizzati e recuperati Verbatim?

Altri suggerimenti

La risposta potrebbe essere quella di memorizzare i valori doppie 17 significativi stringhe di cifre. Guardate la differenza tra come SQLite gestisce i numeri reali vs. testo (io illustrare con l'interfaccia a riga di comando, per semplicità):

sqlite> create table t1(dr real, dt varchar(25));
sqlite> insert into t1 values(0.56657011973046234,'0.56657011973046234');
sqlite> select * from t1;
0.566570119730462|0.56657011973046234

Memorizzazione con vera affinità è la causa del problema - SQLite dà solo di eseguire un'approssimazione di 15 cifre. Se invece si memorizza come testo, è possibile recuperare la stringa originale con il vostro programma C # e riconvertirlo in doppio originale.

Supponendo che sia SQL Lite e NET attuare correttamente la specifica IEEE, si dovrebbe essere in grado di ottenere gli stessi risultati numerici se si è utilizzato lo stesso tipo virgola mobile su entrambi i lati (perché il valore non deve essere modificato quando passato da database per C # e viceversa).

Al momento si sta utilizzando 8 byte IEEE in virgola mobile (singolo) (*) in SQL Lite e 16 byte in virgola mobile in C # (doppio). Il tipo float in C # corrisponde alla 8 byte standard IEEE, in modo da utilizzare questo tipo anziché double potrebbe risolvere il problema.

(*) La documentazione di SQL Lite dice che il Real è un valore in virgola mobile, memorizzato come un numero in virgola mobile IEEE 8 byte .

È possibile utilizzare una stringa per memorizzare il # nel db. Personalmente ho fatto quello che Winwaed suggerito di arrotondare prima di riporlo e dopo il recupero dal db (che ha usato numerica ()).

I ricordo di essere stato bruciato dai banchieri di arrotondamento, ma potrebbe essere solo che non ha soddisfatto le specifiche.

È possibile memorizzare il doppio come una stringa, e utilizzando la formattazione di andata e ritorno durante la conversione del doppio in una stringa, è garantito per generare lo stesso valore quando analizzato:

string formatted = theDouble.ToString("R", CultureInfo.Invariant);

Se si desidera che i valori di input decimali per andata e ritorno, allora si dovrà limitare a 15 cifre significative. Se si desidera che i valori in virgola mobile al SQLite interna a doppia precisione per andata e ritorno, allora si potrebbe essere fuori di fortuna; che richiede la stampa ad un minimo di 17 cifre significative, ma da quello che posso dire, SQLite li stampa a un massimo di 15 ( Modifica :? forse un esperto SQLite può confermare questo ho appena letto il codice sorgente e tracciato esso -. avevo ragione, la precisione è limitata a 15 cifre)

Ho provato il vostro esempio nella interfaccia di comando SQLite su Windows. Ho inserito ,56657011973046234, e selezionare tornato 0,566570119730462. In C, quando ho assegnato ,566570119730462 ad un doppio e stampato a 17 cifre, ho ottenuto 0,56657011973046201; che è lo stesso valore che si ottiene da C #. 0,56657011973046234 e ,56657011973046201 mappa per diversi numeri in virgola mobile, quindi in altre parole, lo SQLite non fa il doppio di andata e ritorno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top