Vraag Bepaal het aantal decimalen met BigDecimal


Ik was geïnteresseerd om de volgende functie getNumberOfDecimalPlace te hebben:

    System.out.println("0 = " + Utils.getNumberOfDecimalPlace(0));          // 0
    System.out.println("1.0 = " + Utils.getNumberOfDecimalPlace(1.0));      // 0
    System.out.println("1.01 = " + Utils.getNumberOfDecimalPlace(1.01));    // 2
    System.out.println("1.012 = " + Utils.getNumberOfDecimalPlace(1.012));  // 3
    System.out.println("0.01 = " + Utils.getNumberOfDecimalPlace(0.01));    // 2
    System.out.println("0.012 = " + Utils.getNumberOfDecimalPlace(0.012));  // 3

Mag ik weten hoe ik getNumberOfDecimalPlace kan implementeren door BigDecimal te gebruiken?

De volgende code werkt niet zoals verwacht:

public static int getNumberOfDecimalPlace(double value) {
    final BigDecimal bigDecimal = new BigDecimal("" + value);
    final String s = bigDecimal.toPlainString();
    System.out.println(s);
    final int index = s.indexOf('.');
    if (index < 0) {
        return 0;
    }
    return s.length() - 1 - index;
}

Het volgende wordt afgedrukt:

0.0
0 = 1
1.0
1.0 = 1
1.01
1.01 = 2
1.012
1.012 = 3
0.01
0.01 = 2
0.012
0.012 = 3

Voor geval 0, 1.0 werkt het echter niet goed. Ik verwacht, "0" als resultaat. Maar ze bleken "0.0" en "1.0" te zijn. Hierdoor wordt "1" als resultaat geretourneerd.


11
2018-02-19 12:08


oorsprong


antwoorden:


Deze code:

int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
    String string = bigDecimal.stripTrailingZeros().toPlainString();
    int index = string.indexOf(".");
    return index < 0 ? 0 : string.length() - index - 1;
}

... slaagt voor deze tests:

assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.001")), equalTo(3));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.01")), equalTo(2));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("0.1")), equalTo(1));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.000")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.00")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1.0")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("1")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10")), equalTo(0));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.1")), equalTo(1));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.01")), equalTo(2));
assertThat(getNumberOfDecimalPlaces(new BigDecimal("10.001")), equalTo(3));

... als dat inderdaad is wat je wilt. De andere antwoorden zijn correct, je moet BigDecimal helemaal gebruiken voor dit in plaats van dubbel / zwevend.


28
2018-01-04 09:10



Het combineren Turismo, Robert en user1777653's antwoorden, we hebben:

int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
    return Math.max(0, bigDecimal.stripTrailingZeros().scale());
}
  • stripTrailingZeros () zorgt ervoor dat volgnullen niet worden geteld (bijv. 1.0 heeft 0 decimalen).
  • scale() is efficiënter dan String.indexOf().
  • Een negatief scale() staat voor nul decimalen.

Daar heb je het, het beste van beide werelden.


22
2018-05-27 00:18



Het is niet jouw code die fout is, maar jouw verwachtingen. double is gebaseerd op een binaire drijvende-komma-weergave en volledig ongeschikt voor het nauwkeurig weergeven van decimale breuken. Decimaal 0,1, b.v. heeft een oneindig aantal cijfers als het wordt weergegeven in binair, dus wordt het afgekapt en wanneer het wordt geconverteerd naar decimaal, krijg je erros in de minst significante cijfers.

Als je gebruikt BigDecimal exclusief, werkt uw code zoals verwacht.


3
2018-02-19 12:45



Als je echt verdubbelt, raad ik aan om ze eerst als string te formatteren voordat je de BigDecimal. Dat heeft tenminste voor mij gewerkt: Hoe te controleren of een double maximaal n decimaal heeft?

Afhankelijk van het aantal cijfers dat u verwacht, kunt u ofwel standaardformattering-achtig gebruiken

String.valueOf(doubleValue);

of u kunt gespecialiseerde opmaak gebruiken om een ​​exponentieel formaat te voorkomen

DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
// don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);

Wanneer je een hebt BigDecimal je kunt gewoon bellen scale() om het aantal decimalen te krijgen.


3
2018-02-19 12:54



Probeer dit:

Math.floor(Math.log(x) / Math.log(10))
0.001 = -3
0.01  = -2
0.1   = -1  
1     = 0  
10    = 1  
100   = 2

2
2018-05-23 13:49



Dat zou het moeten doen

int getNumberOfDecimalPlace(BigDecimal number) {
    int scale = number.stripTrailingZeros().scale();
    return scale > 0 ? scale : 0;
}

1
2017-11-14 21:01



Wat dacht je van een kijkje nemen in de javadoc van BigDecimal. Ik weet het niet zeker, maar ik zou getScale en getPercision eens proberen.


0
2018-02-19 12:11