2016-05-25 24 views
5

Ho un problema con una semplice moltiplicazione che non riesco a capire ... Sto lavorando con .Net Framework 4 e sto costruendo in x86. Sto eseguendo il seguente codice:Doppia moltiplicazione in C#

double x = 348333.673899683; 
double y = 4521014.98461396; 
double aux = x * y; 

Il valore previsto per aux è 1574821759346,09949827752137468 (l'ho fatto con una semplice calcolatrice). Tuttavia, il valore che ottengo in aux è . Vedi che è non un errore di precisione, anche la parte numero intero è stata cambiata.

Se inserisco un punto di interruzione nella moltiplicazione e passa il mouse sopra l'operatore de *, vedo x * y = 1574821759346,0994 che è ok. Se mi passa il mouse sopra la variabile aux vedo aux = 1574821822464

Al fine di chiarire l'ultimo paragrafo, due immagini può essere visto sotto:

enter image description here

enter image description here

In primo luogo, ho pensato che forse è dovuto alla compilazione x86, ma leggendo il prossimo post, ho scartato questa opzione:

The Double Byte Size in 32 bit and 64 bit OS

Non riesco a capire cosa sta succedendo qui. Qualsiasi aiuto sarà apprezzato.

--- EDIT CON PIU 'INFORMAZIONI ---

Sto usando VS2015. Ho aggiunto altre tre linee di debug:

log.Info(x); 
log.Info(y); 
log.Info(aux); 

per mostrare i registri sto usando la libreria log4net. L'uscita è:

23322 [8] INFO Art.Model.Scenarios (null) - 348333,673899683 
24745 [8] INFO Art.Model.Scenarios (null) - 4521014,98461396 
26274 [8] INFO Art.Model.Scenarios (null) - 1574821822464 

Quindi non è un bug nel debugger. Se creo un progetto e una soluzione completamente nuovi funziona, ma non riesco a capire perché non funzioni in questa soluzione.

--- SECONDO EDIT ---

Grazie ai commenti che ho provato qualcosa di nuovo:

double x = 348333.673899683; 
double y = 4521014.98461396; 
double aux = x * y; 

decimal xx = 348333.673899683m; 
decimal yy = 4521014.98461396m; 
decimal auxx = xx * yy; 

log.Info(x); 
log.Info(y); 
log.Info(aux); 

log.Info(xx); 
log.Info(yy); 
log.Info(auxx); 

e il risultato è:

16129 [8] INFO Art.Model.Scenarios (null) - 348333,673899683 
16145 [8] INFO Art.Model.Scenarios (null) - 4521014,98461396 
16145 [8] INFO Art.Model.Scenarios (null) - 1574821822464 
16145 [8] INFO Art.Model.Scenarios (null) - 348333,673899683 
16145 [8] INFO Art.Model.Scenarios (null) - 4521014,98461396 
16145 [8] INFO Art.Model.Scenarios (null) - 1574821759346,0994982775213747 

così funziona con il decimale ma non con il doppio. Qualcuno può spiegarlo? Non riesco a capire perché sta succedendo.

+4

sei sicuro che non sia un problema di debugger? cosa dice Console.WriteLine? Eseguo questo codice nella finestra interattiva vs2015 C# e fornisce la risposta corretta – pm100

+0

quale versione vs? – pm100

+0

VS 2015 finestra di esecuzione U2: 1574821759346,0994 – Dbl

risposta

1

Molto probabilmente, nel caso in cui si utilizza DirectX (l'unica ragione che posso trovare dietro la problematica), questo problema sembra legato al fatto che ogni volta che un dispositivo è stato creato e/o manipolato, costringe la FPU alla singola modalità di precisione, perdendo così la precisione e causando il troncamento di variabili doppie, lunghe e decimali. Se provo un convertitore in virgola mobile IEEE-754 e inserisco i tuoi dati, ottengo questo risultato, che è proprio il tuo caso: i tuoi dati, a un certo punto, sono stati letti come un numero a precisione doppia, ma poi sono stati troncati in un singolo .precision numero in virgola mobile, come si può vedere:

enter image description here

Questo problema può essere risolto con la costruzione esplicitamente l'oggetto periferiche nel FpuPreserve bandiera.

Avevo anche questo problema, e all'inizio però per il cast non corretto o così, fino a dopo una lunga traccia ho scoperto che i valori venivano troncati dopo aver creato un oggetto Device DirectX.

0

Il fenomeno si verifica a causa della definizione dei tipi di dati.

doppio: "Precisione. Quando si lavora con numeri in virgola mobile, ricordate che non sempre hanno una rappresentazione precisa in memoria “ https://msdn.microsoft.com/en-us//de/library/x99xtshc.aspx

decimali:“. Rispetto ai tipi a virgola mobile, il tipo decimale ha una maggiore precisione e una più piccola gamma, che lo rende adatto per i calcoli finanziari e monetari.” https://msdn.microsoft.com/en-us//library/364x0z75.aspx

Tipi doppio di dati vengono memorizzati come frazione binaria, a causa di questo, non possono esatto rappresentato, se questo non è una frazione binaria. https://msdn.microsoft.com/en-us//ae382yt8