2009-07-03 5 views
33

Kann jemand eine effiziente Art und Weise der Bestimmung, ob eine BigDecimal ist ein ganzzahliger Wert im mathematischen Sinne empfehlen?Prüfen, ob BigDecimal ganzzahliger Wert ist

Derzeit habe ich den folgenden Code:

private boolean isIntegerValue(BigDecimal bd) { 
    boolean ret; 

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

    return ret; 
} 

... aber möchte die Objekterstellung Overhead bei Bedarf vermeiden. Zuvor verwendete ich bd.longValueExact(), die das Erstellen eines Objekts vermeiden würde, wenn die BigDecimal ihre kompakte Darstellung intern verwendet, aber offensichtlich fehlschlagen würde, wenn der Wert zu groß wäre, um in ein Long zu passen.

Jede Hilfe wird geschätzt.

+3

Komisch - Ich kann 5 Antworten auf mein Profil sehen, aber wenn ich zu der Frage navigiere, sehe ich nur diese beiden. Ist das Absicht? (d. h. Ist die Antwort unterdrückt, nachdem ich eine Antwort akzeptiert habe?) – Adamski

Antwort

11

Abhängig von der Quelle/Verwendung Ihrer BigDecimal Werte könnte es schneller sein zu überprüfen, ob die Skala < = 0 zuerst ist. Wenn ja, ist es definitiv ein ganzzahliger Wert im mathematischen Sinne. Wenn es> 0 ist, dann könnte es immer noch ein ganzzahliger Wert sein und der teurere Test wäre erforderlich.

+0

Danke - Ich weiß nicht, warum ich nicht darüber nachgedacht habe, und es ist eine gute Optimierung für diese Methode, da ich davon ausgehe, dass der Check 99% der Zeit übersteht. – Adamski

2

Eine Möglichkeit sollte sein, zu überprüfen, ob scale() Null oder negativ ist. In diesem Fall sollte das BigDecimal keine Nachkommastellen haben und die Zahl sollte eine mathematische Ganzzahl sein, wenn ich Ihre Frage richtig verstanden habe.

Update: Wenn positiv, könnte es immer noch eine Ganzzahl sein, aber Sie können nicht extra Objektkreationen für weitere eingehende Prüfungen in diesem Fall verschonen. Ein Beispiel für einen solchen Fall ist bei der stripTrailingZeros() Methode Javadoc gegeben (danke Joachim für den Hinweis in seiner Antwort).

3

Sie können diese verwenden (nur von anderen Antworten zusammenfasst):

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

stripTrailingZeros() ist jedoch eine ziemlich teure Operation.Wahrscheinlich möchten Sie die Skalierung zuerst direkt auf "bd" durchführen. – mikera

+3

Sorry, es funktioniert nicht wegen des Java-Bugs, bei dem 'stripTrailingZeros' keinen Effekt auf 0 hat (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6480539). Und wie andere gesagt haben, ist es auch langsam, zumal "stripTrailingZeros" nicht nur fehlerhaft ist, sondern auch vom Performance-Standpunkt her eine schlechte Qualität hat. – ddekany

+0

Der Fehler, auf den sich @ddekany bezieht, wurde behoben – softarn

48

Wenn Sie die scale() und stripTrailingZeros() Lösung in einigen der Antworten erwähnt verwenden Sie die Aufmerksamkeit auf Null bezahlen sollte. Zero ist immer eine Ganzzahl, unabhängig davon, welche Skalierung es hat, und stripTrailingZeros() ändert nicht die Skalierung einer Null BigDecimal.

So könnte man so etwas tun:

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

Dies ist das sauberste, das ich habe kommen mit.

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

Teilen Sie die Zahl durch 1 und prüfen Sie auf einen Rest. Jede ganze Zahl sollte immer einen Rest von 0, wenn dividiert durch 1.

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

Es könnte sich lohnen, 'number.scale() <= 0 || hinzuzufügen ... bevor Sie den Rest berechnen und auf Null prüfen, um unnötigen Overhead zu vermeiden, wenn die Skala anzeigt, dass es sich definitiv um eine Ganzzahl handelt. – megaflop

0

Dies kann auf die gleiche Weise durchgeführt werden, dass jemand würde überprüfen, ob eine Doppel eine ganze Zahl, die Durchführung% 1 == 0. Dies So würde es nach einem BigDecimal-Wert aussehen.

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