使用BigDecimal确定小数位数

时间:2010-02-19 12:08:12

标签: java

我有兴趣拥有以下getNumberOfDecimalPlace功能:

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

我是否可以通过getNumberOfDecimalPlace

了解如何实施BigDecimal

以下代码无法按预期工作:

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;
}

以下内容打印出来:

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

然而,对于案例0,1.0,它不能很好地工作。我期待,结果是“0”。但结果却是“0.0”和“1.0”。这将返回“1”。

12 个答案:

答案 0 :(得分:32)

此代码:

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

...通过了这些测试:

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));

......如果那确实是你想要的。其他回复都是正确的,你必须一直使用BigDecimal而不是double / float。

答案 1 :(得分:29)

结合TurismoRobertuser1777653's答案,我们得到了:

int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
    return Math.max(0, bigDecimal.stripTrailingZeros().scale());
}
  • stripTrailingZeros()确保不计算尾随零(例如1.0有0位小数)。
  • scale()String.indexOf()更有效。
  • 否定scale()表示零小数位。

你有它,两全其美。

答案 2 :(得分:3)

这不是你的代码错了,而是你的期望。 double基于二进制浮点表示,完全不适合精确表示小数部分。十进制0.1例如当以二进制表示时,它具有无限数量的数字,因此它被截断,当转换回十进制时,你得到最低有效数字的错误。

如果您独占使用BigDecimal,您的代码将按预期运行。

答案 3 :(得分:3)

如果你真的得到双打,我建议在创建BigDecimal之前先将它们格式化为字符串。至少那对我有用:How to check if a double has at most n decimal places?

根据您期望的位数,您可以使用标准格式化

String.valueOf(doubleValue);

或者您可以使用专门的格式来避免指数格式

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);

如果您有BigDecimal,只需拨打scale()即可获得小数位数。

答案 4 :(得分:2)

试试这个:

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

答案 5 :(得分:2)

应该这样做

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

答案 6 :(得分:2)

无需转换为String,直接使用比例应该更有效:

  private int getNumberOfDecimalPlaces(BigDecimal bigDecimal)
  {
    int scale =  bigDecimal.stripTrailingZeros().scale();
    return scale>0?scale:0;
  }

答案 7 :(得分:0)

如何看看BigDecimal的javadoc。我不确定,但我会试试getScale和getPercision。

答案 8 :(得分:0)

获取具有指定小数位数的BigDecimal的最佳方法是使用setscale方法。我个人也喜欢使用该方法的舍入版本(见下面的链接): http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#setScale(int,%20int)

如果您想要获取BigDecimal当前设置的小数位数,请调用相关的scale()方法。

答案 9 :(得分:0)

到目前为止我找到的最佳选项(不需要toString + index):

analysis.include

答案 10 :(得分:-1)

迈克尔博格沃德的回答是正确的。只要您使用任何double或float,您的值就已经损坏。

提供代码示例:

System.out.println("0 = " + BigDecimalUtil.getNumberOfDecimalPlace("0")); // 0
System.out.println("1.0 = " + BigDecimalUtil.getNumberOfDecimalPlace("1.0")); // 0
System.out.println("1.01 = " + BigDecimalUtil.getNumberOfDecimalPlace(new BigDecimal("1.01"))); // 2
System.out.println("1.012 = " + BigDecimalUtil.getNumberOfDecimalPlace(new BigDecimal("1.012"))); // 3
System.out.println("0.01 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.01")); // 2
System.out.println("0.012 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.012")); // 3
System.out.println("0.00000000000000000012 = " + BigDecimalUtil.getNumberOfDecimalPlace("0.00000000000000000012")); // 20

getNumberOfDecimalPlace的重载版本,因此您可以将它与BigDecimal或String一起使用:

public static int getNumberOfDecimalPlace(String value) {
    final int index = value.indexOf('.');
    if (index < 0) {
        return 0;
    }
    return value.length() - 1 - index;
}

public static int getNumberOfDecimalPlace(BigDecimal value) {
    return getNumberOfDecimalPlace(value.toPlainString());
}

答案 11 :(得分:-6)

为什么不直接更改代码以获得双倍小数位?

public static int getNumberOfDecimalPlace(double value) {
    //For whole numbers like 0
    if (Math.round(value) == value) return 0;
    final String s = Double.toString(value);
    System.out.println(s);
    final int index = s.indexOf('.');
    if (index < 0) {
       return 0;
    }
    return s.length() - 1 - index;
}