2009-07-03 24 views
33

Qualcuno può consigliare un efficiente modo di determinare se uno BigDecimal è un valore intero in senso matematico?Verifica se BigDecimal è un valore intero

Al momento ho il seguente codice:

private boolean isIntegerValue(BigDecimal bd) { 
    boolean ret; 

    try { 
     bd.toBigIntegerExact(); 
     ret = true; 
    } catch (ArithmeticException ex) { 
     ret = false; 
    } 

    return ret; 
} 

... ma vorrei evitare il sovraccarico creazione di oggetti, se necessario. Precedentemente stavo usando bd.longValueExact() che eviterebbe di creare un oggetto se lo BigDecimal usasse la sua rappresentazione compatta internamente, ma ovviamente fallirebbe se il valore fosse troppo grande per adattarsi a un lungo.

Qualsiasi aiuto apprezzato.

+3

Strano - Vedo 5 risposte sul mio profilo ma quando navigo alla domanda vedo solo queste due. È questo in base alla progettazione? (Ad esempio, la risposta è stata soppressa dopo aver accettato una risposta?) – Adamski

risposta

11

A seconda dell'origine/utilizzo dei valori BigDecimal, potrebbe essere più veloce verificare prima se la bilancia < = 0. Se lo è, allora è sicuramente un valore intero in senso matematico. Se è> 0, allora potrebbe essere ancora un valore intero e il test più costoso sarebbe necessario.

+0

Grazie - Non so perché non ci ho pensato, ed è una buona ottimizzazione per questo metodo, in quanto prevedo che il controllo passi il 99% delle volte. – Adamski

2

Una possibilità dovrebbe essere quella di verificare se scale() è zero o negativo. In tal caso, il BigDecimal non dovrebbe avere cifre dopo il punto decimale e il numero dovrebbe essere un numero intero matematico se ho compreso correttamente la tua domanda.

Aggiornamento: Se positivo, potrebbe essere ancora un numero intero, ma in questo caso non è possibile risparmiare ulteriori creazioni di oggetti per ulteriori controlli approfonditi. Un esempio per un caso del genere è dato al metodo stripTrailingZeros() javadoc (grazie a Joachim per il suggerimento nella sua risposta).

3

È possibile utilizzare questo (basta che riassume da altre risposte):

private boolean isIntegerValue(BigDecimal bd) { 
    return bd.stripTrailingZeros().scale() <= 0; 
} 
+3

stripTrailingZeros() è un'operazione piuttosto costosa.Probabilmente vorresti fare il controllo della scala direttamente su 'bd' prima. – mikera

+3

Siamo spiacenti, non funziona a causa del bug Java in cui 'stripTrailingZeros' non ha alcun effetto su 0 (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6480539). E come detto anche è lento, specialmente perché 'stripTrailingZeros' non è solo buggato, ma ha anche un'implementazione di scarsa qualità dal punto di vista delle prestazioni. – ddekany

+0

Il bug a cui @ddekany si riferisce è stato corretto – softarn

48

Se si utilizza la soluzione scale() e stripTrailingZeros() citato in alcune delle risposte si dovrebbe prestare attenzione a zero. Zero è sempre un numero intero indipendentemente dalla scala in cui si trova e stripTrailingZeros() non modifica la scala di un BigDecimal zero.

Così si potrebbe fare qualcosa di simile:

private boolean isIntegerValue(BigDecimal bd) { 
    return bd.signum() == 0 || bd.scale() <= 0 || bd.stripTrailingZeros().scale() <= 0; 
} 
0

Questo è il più pulito che è venuta in mente.

public static boolean isWhole(BigDecimal bigDecimal) { 
    return bigDecimal.setScale(0, RoundingMode.HALF_UP).compareTo(bigDecimal) == 0; 
} 
3

Dividere il numero per 1 e controllare un resto. Qualsiasi numero intero dovrebbe avere sempre un resto di 0 quando diviso per 1.

public boolean isWholeNumber(BigDecimal number) { 
    return number.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) == 0; 
} 
+1

Potrebbe valere la pena di aggiungerlo in 'number.scale() <= 0 || ... 'prima di calcolare il resto e verificare a zero, per evitare un sovraccarico non necessario quando la scala indica che è sicuramente un numero intero. – megaflop

0

Ciò può essere fatto allo stesso modo che qualcuno controllare se un doppio è un numero intero, eseguendo% 1 == 0. Questo è come dovrebbe cercare un valore BigDecimal.

public static boolean isIntegerValue(BigDecimal bd){ 
    return bd.remainder(new BigDecimal("1")).compareTo(BigDecimal.ZERO) == 0; 
} 
Problemi correlati