2012-03-01 11 views
6

Ho convertito un algoritmo relativamente semplice che esegue un gran numero di calcoli su numeri del tipo double da C++ a Java, tuttavia eseguendo l'algoritmo sulle due piattaforme ma la stessa macchina produce risultati leggermente diversi. L'algoritmo moltiplica e somma molti doppi e interi. Sto facendo il casting per raddoppiare nell'algoritmo di Java; l'algoritmo C non esegue il cast.Come confermare se i diversi risultati sono dovuti a differenze nella gestione in virgola mobile?

Per esempio, su una corsa ottengo i risultati:

  • (Java) 64.684.970
  • (C++) 65296408

(stampato a ignorare decimale)

Naturalmente , potrebbe esserci un errore nel mio algoritmo, tuttavia prima di iniziare a spendere il debugging del tempo, è possibile che la differenza possa essere spiegata da una diversa gestione in virgola mobile in C++ e Ja va? In tal caso, posso provare che questo è il problema?


Update - il luogo dove i tipi differiscono è una moltiplicazione tra due interi che viene poi aggiunto a un totale doppia corsa. aver modificato il codice C, attualmente in entrambi:

mydouble += (double)int1 * (double)int2

+0

Quale tipo di dati è stato utilizzato nella versione Java? – wallyk

+4

Questa è una differenza, e dubito che possa essere causato da errori di arrotondamento. La mia ipotesi è che tu abbia commesso un errore da qualche parte. A meno che tu non faccia cose estreme come la divisione per 1E300 e cose del genere. –

+0

@wallyk: doppio. – Brabster

risposta

2

mi risulta, ci sono momenti in cui il valore di una doppia letterale potrebbe cambiare tra due versioni C++ (quando l'algoritmo utilizzato per convertire la sorgente al successivo valore doppio migliore è cambiato).

Anche su alcuni cpus i registri in virgola mobile sono più grandi di 64/32 bit (maggiore portata e precisione) e il modo in cui questo influenza il risultato dipende da come il compilatore e JIT spostano i valori dentro e fuori da questi registri - è probabile che differiscono tra java e C++.

Java ha la parola chiave strictftp per garantire che venga utilizzata solo la precisione a 64/32 bit, tuttavia con un costo di runtime. Ci sono anche un gran numero di opzioni per influenzare il modo in cui i compilatori C++ trattano e ottimizzano i calcoli in virgola mobile eliminando garanzie/regole stabilite dallo standard IEEE.

se l'algoritmo è per lo più lo stesso, è possibile controllare dove appare la prima differenza per lo stesso input.

+0

In questo caso il controllo dell'uscita passo passo ha identificato il passo divergente e mi ha indicato una differenza nei dati. Dopo aver corretto che gli algoritmi sono d'accordo. – Brabster

3

si potrebbe aggiungere l'arrotondamento per ogni algoritmo utilizzando la stessa precisione. Ciò consentirebbe a ciascun calcolo di gestire i dati allo stesso modo. Se si utilizza questo, eliminerebbe l'algoritmo essendo il problema poiché i dati utilizzerebbero la stessa precisione in ogni fase dell'equazione per entrambe le versioni C++ e Java

+0

A meno che non manchi qualcosa, l'arrotondamento potrebbe ridurre il numero di volte in cui c'è un problema, ma non eliminerebbe tutti i problemi? Potresti ancora arrotolare una differenza di precisione nel galleggiante arrotondato meno preciso, credo? Come se su cpu fosse 95.499999994 e l'altro dia 95.499999995 e tu arrotondassi con quella precisione, otterrai valori diversi anche se meno decimali? –

1

In Java, il doppio è un floating a 64 bit. numero del punto. In C++, il doppio è un numero in virgola mobile garantito con una precisione almeno di 32 bit.

Per trovare la dimensione effettiva, in byte, di un doppio C++ sul sistema, utilizzare sizeof (double).

Se risulta che sizeof (double) == 8, è quasi certo che la differenza è dovuta a un errore nella traduzione da una lingua a un'altra, piuttosto che le differenze nella gestione dei numeri in virgola mobile.

(Tecnicamente, la dimensione di un byte dipende dalla piattaforma, ma la maggior parte delle architetture moderni utilizzano byte di 8 bit.)

Problemi correlati