如何检查双数是否至多有n位小数? [英] How to check if a double has at most n decimal places?

查看:182
本文介绍了如何检查双数是否至多有n位小数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



$ $ $ $ $ $ $ $ $ $ $ $ $ $ $如果($ d == 0)返回true;

double multiplier = Math.pow(10,decimalPlaces);
double check = d * multiplier;
check = Math.round(check);
check = check / multiplier;
return(d == check);





$ b

但是这个方法在 checkDecmialPlaces(649632196443.4279,4 )可能是因为我在一个基数为2的数字上做了10个数学计算。

那么这个检查怎么能正确完成呢? b
$ b

我想要得到一个double值的字符串表示,然后使用正则表达式来检查它 - 但是这样感觉很奇怪。编辑:
感谢所有的答案。有些情况下,我真的得到了一个双重和这些情况下,我执行以下:

$ pre $私人静态布尔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<小量;

$ / code>

我改变了截断。似乎在 round 中完成的计算过多地增加了不准确性。至少在失败的测试用例中。

正如你们中的一些人指出的,如果我能得到真正的字符串输入,我应该使用 BigDecimal 来检查所以我做了:

  BigDecimal decimal = new BigDecimal(value); 
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
返回checkDecimal.scale()== 0;

我得到的 double 读取excel文件的Apache POI API。我做了一些测试,发现尽管API为数字单元格返回 double 值,但是当我立即格式化 double DecimalFormat
$ b $ $ $ $ $ $ $ $ $ $>十进制格式decimalFormat =新的DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
//不要使用数组类型的单元格
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(新的DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);

这也适用于无法用二进制格式精确表示的值。 b $ b

解决方案

测试失败,因为您已达到二进制浮点表示法的精确度,该表达式的大小约为16位,其中 IEEE754双精度。乘以649632196443.4279乘以10000会截断二进制表示,导致四舍五入后的错误,从而使函数的结果完全失效。

有关更多详细信息,请参阅 http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

b
$ b

更好的方法是检查 n + 1 小数位数是否低于某个阈值。如果 d - round(d)小于 epsilon (请参阅限制), d 的十进制表示没有重要的小数位数。同样,如果(d-round(d))* 10 ^ n 小于 epsilon ,则d最多可以有 n 显着位置。

使用 Jon Skeet DoubleConverter 检查以下情况: code> d 不够精确,无法保存您要查找的小数位。


Currently i have this method:

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

But this method fails for checkDecmialPlaces(649632196443.4279, 4) probably because I do base 10 math on a base 2 number.

So how can this check be done correctly?

I thought of getting a string representation of the double value and then check that with a regexp - but that felt weird.

EDIT: Thanks for all the answers. There are cases where I really get a double and for those cases I implemented the following:

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

I changed the round to a truncation. Seems that the computation done in round increases the inaccuracy too much. At least in the failing testcase.
As some of you pointed out if I could get to the 'real' string input I should use BigDecimal to check and so I have done:

BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;

The double value I get comes from the Apache POI API that reads excel files. I did a few tests and found out that although the API returns double values for numeric cells I can get a accurate representation when I immediately format that double with the 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);

This also works for values that can't be represented exactly in binary format.

解决方案

The test fails, because you have reached the accuracy of the binary floating point representation, which is approximately 16 digits with IEEE754 double precision. Multiplying by 649632196443.4279 by 10000 will truncate the binary representation, leading to errors when rounding and dividing afterwards, thereby invalidating the result of your function completely.

For more details see http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

A better way would be to check whether the n+1 decimal places are below a certain threshold. If d - round(d) is less than epsilon (see limit), the decimal representation of d has no significant decimal places. Similarly if (d - round(d)) * 10^n is less than epsilon, d can have at most n significant places.

Use Jon Skeet's DoubleConverter to check for the cases where d isn't accurate enough to hold the decimal places you are looking for.

这篇关于如何检查双数是否至多有n位小数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆