目前我有这个方法:
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值的字符串表示,然后用regexp检查 - 但这感觉很奇怪.
编辑: 谢谢你的所有答案.在某些情况下,我真的得到了一个双倍,在这些情况下,我实现了以下内容:
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
的数字单元格的值,我可以得到一个精确的表示时,我立即格式化double
用DecimalFormat
:
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);
这也适用于无法以二进制格式精确表示的值.
如果您的目标是在小数点右侧表示一个具有正确n个有效数字的数字,则BigDecimal是要使用的类.
不可变的,任意精度的带符号十进制数.BigDecimal由任意精度整数非标度值和32位整数标度组成.如果为零或正数,则比例是小数点右侧的位数.如果是负数,则将数字的未缩放值乘以10来表示比例的否定.因此,BigDecimal表示的数字的值是(unscaledValue×10-scale).
scale
可以通过setScale(int)设置
测试失败,因为您已达到二进制浮点表示的精度,大约是16位数,具有IEEE754双精度.乘以649632196443.4279乘以10000会截断二进制表示,导致后续舍入和除法时出错,从而使函数的结果完全失效.
有关详细信息,请参阅http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
更好的方法是检查n+1
小数位是否低于某个阈值.如果d - round(d)
小于epsilon
(见限制),则十进制表示d
没有显着的小数位.同样,如果(d - round(d)) * 10^n
小于epsilon
,则d可以具有最多n
显着位置.
使用乔恩斯基特的DoubleConverter
检查,其中情况d
不够准确抱着你正在寻找的小数位.