Tur*_*smo 10 java floating-point decimal
目前我有这个方法:
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);
}
Run Code Online (Sandbox Code Playgroud)
但是这种方法失败的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;
}
Run Code Online (Sandbox Code Playgroud)
我把它改成round了截断.似乎所做的计算round过多地增加了不准确性.至少在失败的测试用例中.
正如你们中的一些人指出我是否可以使用"真正的"字符串输入我应该BigDecimal用来检查,所以我做了:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
这也适用于无法以二进制格式精确表示的值.
如果您的目标是在小数点右侧表示一个具有正确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不够准确抱着你正在寻找的小数位.