目前我有这个方法:
static boolean checkDecimalPlaces(double d, int decimalPlaces){
if (d==0) return true;
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
check = Math.round(check);
check = check/multiplier;
return (d==check);
}
但此方法对于 checkDecmialPlaces(649632196443.4279, 4)
失败可能是因为我在基数 2 上进行基数 10 的数学计算。
那么如何才能正确完成这项检查呢?
我想获取 double 值的字符串表示形式,然后使用正则表达式对其进行检查 - 但感觉很奇怪。
编辑: 感谢所有的答案。在某些情况下,我真的得到了一个双倍,对于这些情况,我实现了以下操作:
private static boolean checkDecimalPlaces(double d, int decimalPlaces) {
if (d == 0) return true;
final double epsilon = Math.pow(10.0, ((decimalPlaces + 1) * -1));
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
long checkLong = (long) Math.abs(check);
check = checkLong / multiplier;
double e = Math.abs(d - check);
return e < epsilon;
}
我将 round
更改为截断。似乎在 round
中完成的计算增加了太多的不准确性。至少在失败的测试用例中。
正如你们中的一些人指出的那样,如果我可以得到“真实的”字符串输入,我应该使用 BigDecimal
来检查,所以我已经完成了:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
我得到的 double
值来自读取 excel 文件的 Apache POI API。我做了一些测试,发现尽管 API 返回数字单元格的 double
值,但当我立即使用 DecimalFormat 格式化
:double
时,我可以获得准确的表示
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);
这也适用于无法以二进制格式准确表示的值。
最佳答案
测试失败,因为您已经达到了二进制浮点表示的精度,即 IEEE754 double precision 大约为 16 位数字。 .将 649632196443.4279 乘以 10000 将截断二进制表示形式,导致之后舍入和除法时出错,从而使您的函数结果完全无效。
有关详细信息,请参阅 http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
更好的方法是检查 n+1
小数位是否低于某个阈值。如果 d - round(d)
小于 epsilon
(参见 limit ),d
的十进制表示没有有效的小数位。类似地,如果 (d - round(d)) * 10^n
小于 epsilon
,d 最多可以有 n
有效位置。
使用Jon Skeet的 DoubleConverter
检查 d
不够准确以保留您要查找的小数位的情况。
关于java - 如何检查 double 是否最多有 n 位小数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/264937/