2014-12-01 12 views
14

Ho un gran numero in formato esadecimale (con punto decimale) in una String e voglio convertirlo in un valore BigDecimal.Come convertire il numero grande esadecimale (con punto decimale) per BigDecimal

Esempio: 0xcc.ccdp+1600

in BigDecimal classe, non vedo qualunque funzione che prende stringa che rappresenta il numero in formato esadecimale come input e ritorna corrispondente BigDecimal.

c'è un modo per convertire un gran numero esadecimale da String a BigDecimal?

+0

Sì, c'è sicuramente un modo. Se si desidera un modo che non implichi l'analisi della stringa di input, non sono sicuro. Non vedo alcun metodo 'BigDecimal' che accetti qualsiasi input in qualsiasi radice oltre al decimale. – ajb

+0

Si può sempre rimbalzare attraverso 'BigInteger' ... analizzare entrambi i lati del decimale e quindi concatenare e analizzare. Ci sono probabilmente alcuni modi divertenti per farlo anche numericamente o sottoclasse BigDecimal per modificare la mappatura char-> digit. –

+1

Nota che, in teoria, non è un "punto decimale" ma piuttosto un "punto esadecimale". –

risposta

6

Sono sorpreso che lo BigDecimal non lo supporti già. Ho scritto quanto segue, che penso dovrebbe funzionare. Si passa miei test iniziali (con 0xcc.ccdp+0, 0xcc.ccdp+1, 0xcc.ccdp+16, 0xcc.ccdp+256, e la vostra 0xcc.ccdp+1600, e anche alcuni esponenti negativi, da -1 fino a -16), ma dovrebbe essere testato in modo più approfondito prima di essere utilizzato nel codice di produzione.

private final static BigInteger TWO = BigInteger.valueOf(2); 
private final static BigDecimal MINUS_ONE = new BigDecimal(-1); 

public static BigDecimal toBigDecimal(String hex) { 
    // handle leading sign 
    BigDecimal sign = null; 
    if (hex.startsWith("-")) { 
     hex = hex.substring(1); 
     sign = MINUS_ONE; 
    } else if (hex.startsWith("+")) { 
     hex = hex.substring(1); 
    } 

    // constant must start with 0x or 0X 
    if (!(hex.startsWith("0x") || hex.startsWith("0X"))) { 
     throw new IllegalArgumentException(
       "not a hexadecimal floating point constant"); 
    } 
    hex = hex.substring(2); 

    // ... and end in 'p' or 'P' and an exponent 
    int p = hex.indexOf("p"); 
    if (p < 0) p = hex.indexOf("P"); 
    if (p < 0) { 
     throw new IllegalArgumentException(
       "not a hexadecimal floating point constant"); 
    } 
    String mantissa = hex.substring(0, p); 
    String exponent = hex.substring(p+1); 

    // find the hexadecimal point, if any 
    int hexadecimalPoint = mantissa.indexOf("."); 
    int hexadecimalPlaces = 0; 
    if (hexadecimalPoint >= 0) { 
     hexadecimalPlaces = mantissa.length() - 1 - hexadecimalPoint; 
     mantissa = mantissa.substring(0, hexadecimalPoint) + 
      mantissa.substring(hexadecimalPoint + 1); 
    } 

    // reduce the exponent by 4 for every hexadecimal place 
    int binaryExponent = Integer.valueOf(exponent) - (hexadecimalPlaces * 4); 
    boolean positive = true; 
    if (binaryExponent < 0) { 
     binaryExponent = -binaryExponent; 
     positive = false; 
    } 

    BigDecimal base = new BigDecimal(new BigInteger(mantissa, 16)); 
    BigDecimal factor = new BigDecimal(TWO.pow(binaryExponent)); 
    BigDecimal value = positive? base.multiply(factor) : base.divide(factor); 
    if (sign != null) value = value.multiply(sign); 

    return value; 
} 

Ho released this on github sotto la licenza MIT. Ci sono dei test unitari, ma solo un set abbastanza minimale.

Se trovi dei casi per i quali questo restituisce un valore errato, faccelo sapere.

+1

Grazie per aver fornito la soluzione. Ho fatto alcuni test iniziali e il codice ha funzionato perfettamente. L'unico caso, mi viene in mente in questo momento, è quando il numero memorizzato in String è un numero negativo. Esempio -0xcc.ccdp + 1600. Ma non è difficile aggiungere un controllo per questo. – user2888308

+0

Whoops! Ho perso quello. Buona pesca! –

+0

L'ho aggiornato per gestire i numeri negativi. Dal momento che 'Integer.parseInt()' può anche accettare un unario iniziale più per esempio, '" +42 "' Ho anche fatto ignorare un segno più positivo. –

Problemi correlati