Java 使用 BigDecimal 确定小数位数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2296110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determine Number of Decimal Place using BigDecimal
提问by Cheok Yan Cheng
I was interested to have the following getNumberOfDecimalPlace
function:
我有兴趣拥有以下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
May I know how can I implement getNumberOfDecimalPlace
, by using BigDecimal
?
我可以知道如何getNumberOfDecimalPlace
通过使用来实现BigDecimal
吗?
The following code doesn't work as expected:
以下代码无法按预期工作:
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;
}
The following get printed :
打印以下内容:
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
However, for case 0, 1.0, it doesn't work well. I expect, "0" as result. But they turned out to be "0.0" and "1.0". This will return "1" as result.
但是,对于 case 0, 1.0,效果不佳。我期望结果为“0”。但结果是“0.0”和“1.0”。这将返回“1”作为结果。
采纳答案by Robert Atkins
This code:
这段代码:
int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
String string = bigDecimal.stripTrailingZeros().toPlainString();
int index = string.indexOf(".");
return index < 0 ? 0 : string.length() - index - 1;
}
... passes these 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));
... if that is indeed what you want. The other replies are correct, you have to use BigDecimal all the way through for this rather than double/float.
......如果这确实是你想要的。其他答复是正确的,为此您必须一直使用 BigDecimal 而不是 double/float。
回答by er4z0r
How about having a look at the javadoc of BigDecimal. I'm not sure, but I'd give getScale and getPercision a try.
看看 BigDecimal 的 javadoc 怎么样。我不确定,但我会尝试一下 getScale 和 getPercision。
回答by SOA Nerd
The best way to get a BigDecimal with a specified number of decimal places is by using the setscale method over it. Personally I like to also use the rounding version of the method (see the link below):
http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#setScale(int,%20int)
获得具有指定小数位数的 BigDecimal 的最佳方法是对其使用 setscale 方法。我个人也喜欢使用该方法的舍入版本(请参阅下面的链接):http:
//java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#setScale(int ,%20int)
If you're wanting to get the number of decimal positions that a BigDecimal is currently set at call the associated scale() method.
如果您想获取 BigDecimal 当前设置的小数位数,请调用关联的 scale() 方法。
回答by Clinton
Why not just change your code to get a doubles decimal places?
为什么不更改您的代码以获得双精度小数位?
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;
}
回答by Michael Borgwardt
It's not your code that's wrong, but your expectations. double
is based on a binary floating point representation and completely unfit for accurately representing decimal fractions. Decimal 0.1 e.g. has an infinite number of digits when represented in binary, thus it gets truncated and when converted back to decimal, you get erros in the least significant digits.
错的不是你的代码,而是你的期望。double
基于二进制浮点表示,完全不适合准确表示十进制分数。十进制 0.1 例如在以二进制表示时具有无限数量的数字,因此它会被截断,当转换回十进制时,您会在最低有效数字中出现错误。
If you use BigDecimal
exclusively, your code will work as expected.
如果您BigDecimal
专门使用,您的代码将按预期工作。
回答by Turismo
If you really get doubles i recommend formating them first as strings before creating the BigDecimal
. At least that has worked for me: How to check if a double has at most n decimal places?
如果你真的得到双打,我建议在创建BigDecimal
. 至少这对我有用:如何检查双精度数是否最多有 n 个小数位?
Depending on how many digits you expect you can either use standard formating like
根据您期望的数字数量,您可以使用标准格式,例如
String.valueOf(doubleValue);
or you could use specialised formatting to avoid exponential format
或者您可以使用专门的格式来避免指数格式
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);
When you have a BigDecimal
you can simply call scale()
to get the number of decimal places.
当您有一个时,BigDecimal
您可以简单地调用scale()
以获取小数位数。
回答by Nils Schmidt
Michael Borgwardt answer is the correct one. As soon as you use any double or float, your values are already corrupted.
Michael Borgwardt 的回答是正确的。一旦您使用任何 double 或 float,您的值就已经损坏。
To provide a code example:
提供一个代码示例:
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
And an overloaded version of getNumberOfDecimalPlace so you could use it with BigDecimal or String:
以及 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());
}
回答by Lawrence Phillips
Try this:
尝试这个:
Math.floor(Math.log(x) / Math.log(10))
0.001 = -3
0.01 = -2
0.1 = -1
1 = 0
10 = 1
100 = 2
回答by user1777653
That should do it
那应该这样做
int getNumberOfDecimalPlace(BigDecimal number) {
int scale = number.stripTrailingZeros().scale();
return scale > 0 ? scale : 0;
}
回答by Gili
Combining Turismo, Robertand user1777653'sanswers, we've got:
结合Turismo、Robert和user1777653 的答案,我们得到:
int getNumberOfDecimalPlaces(BigDecimal bigDecimal) {
return Math.max(0, bigDecimal.stripTrailingZeros().scale());
}
- stripTrailingZeros() ensures that trailing zeros are not counted (e.g.
1.0
has 0 decimal places). scale()
is more efficient thanString.indexOf()
.- A negative
scale()
represents zero decimal places.
- stripTrailingZeros() 确保不计算尾随零(例如
1.0
有 0 个小数位)。 scale()
比 更有效率String.indexOf()
。- 负数
scale()
代表零小数位。
There you have it, the best of both worlds.
你有它,两全其美。