Domanda

Sto eseguendo alcune conversioni di tipi di dati in cui devo rappresentare uint, long, ulong e decimal come valori in virgola mobile IEEE 754 doppi. Voglio essere in grado di rilevare se il tipo di dati IEEE 754 non può contenere il valore prima di eseguire la conversione.

Una soluzione di forza bruta sarebbe quella di avvolgere un cast di prova attorno a un cast per raddoppiare la ricerca di OverflowException. Leggendo alcuni dei documentazione CLR implica che alcune conversioni cambiano silenziosamente il valore senza eccezioni.

Esiste un modo infallibile per fare questo controllo? Sto cercando completezza sulla facilità di implementazione. Ho la sensazione che leggerò attentamente le specifiche IEEE 754 e controllerò attentamente matissa ed esponente ...

Dovrei aggiungere che sono più interessato a rappresentare accuratamente numeri interi e che la perdita di precisione in virgola mobile è di secondaria importanza (ma vale comunque la pena considerare).

MODIFICA: Int32 può essere pienamente espresso come IEE-754. Anche il Decimal tipo di dati fa molto parte della domanda.

Aggiornamento importante: se ti riferisci a questa domanda, dovresti anche leggere questa domanda: IEEE-754 Double (Virgola mobile a 64 bit) rispetto a Long (intero a 64 bit) rivisitato

Rileva un difetto nella risposta in cui alcuni valori molto grandi possono anche essere rappresentati esattamente da IEEE-754. Anche se questo può significare che il valore andrà di andata e ritorno correttamente, per il mio scopo originale (andrà di andata e ritorno a JavaScript), non lo farà.

Inoltre sembra che ci sia un bug nel CLRs System.Double type perché non consente correttamente a questi valori di andata e ritorno.

È stato utile?

Soluzione

La soluzione semplice potrebbe essere qualcosa del tipo ( se x è un int ):

if ((int)(double)x != x) { 
  // won't convert
} else {
  // will convert
}

e così via a lungo, ecc.

(doppio) x convertirà x da un int a un doppio. Il (int) lo converte di nuovo. Quindi (int) (double) x converte formano un int in doppio e poi indietro. In sostanza il codice sta verificando che la conversione in double sia reversibile (e quindi che il double possa memorizzare il valore esatto dell'int).

Altri suggerimenti

Ciò dipende principalmente dall'intervallo numerico con cui stai operando. Finché hai meno di 15 cifre (per un double ), dovresti essere sul lato sicuro per numeri interi.

Fondamentalmente, ciò che devi prendere in considerazione è il numero di cifre significative. Quindi finché il numero è inferiore al limite di cifre significative, rimarrà esatto; se diventa più grande, perderai la precisione (anche se quelli sono numeri interi).

Finché il tuo numero è < 2 ^ 53, di solito sei bravo.

IEEE 754 Double ha 52 bit per mantissa e stai convertendo da / a intero / lungo , quindi è abbastanza facile testarlo. Se il tuo numero intero consuma meno di 52 bit, dovrebbe essere convertibile senza problemi in IEEE 754 doppio.

Suppongo (lo so con certezza in caso di Java ma non C # e pigro da controllare) che int è 32 bit e lungo è 64 bit. Quindi sicuramente int può adattarsi al doppio senza alcun problema sia firmare che unsign.

Per ulong, semplicemente se tutti i bit superiori al 52 ° bit sono simili ((aULong & amp; & amp; 0xFFF0000000000000) == 0).

Per molto tempo, devi portare il suo accesso alla considerazione. Dato che Long è il complemento 2, ma IEEE754 non lo è (ha solo un bit negativo), pensa che sia sicuro convertire solo il negativo lungo in positivo (* -1) e controllare come positivo. Quindi, se il long è negativo, cronometra prima con -1 (non fare nulla per positivo). Quindi, controlla come ulong.

Spero che questo aiuti.

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