Java 如何检查double是否最多有n个小数位?
目前我有以下方法:Java 如何检查double是否最多有n个小数位?,java,floating-point,decimal,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/mu
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;
}
我得到的double
值来自读取excel文件的ApachePOIAPI。我做了一些测试,发现尽管API返回数值单元格的double
值,但当我立即用十进制格式设置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);
这也适用于不能以二进制格式精确表示的值。与所有浮点运算一样,不应检查是否相等,而应检查错误(ε)是否足够小
如果更换:
return (d==check);
有点像
return (Math.abs(d-check) <= 0.0000001);
return(Math.abs(d-check)double
类型是一个二进制浮点数。如果将它们当作十进制浮点数来处理,则总是存在明显的不精确性。我不知道您是否能够编写函数以使其按您希望的方式工作
如果对您很重要,您可能必须返回数字的原始来源(可能是字符串输入),并保留十进制表示。如果您的目标是在小数点右侧精确地表示一个数字,则要使用的类是
不可变、任意精度签名
十进制数。大十进制数由
任意精度整数
无标度值和32位整数
刻度。如果为零或正,则刻度为
是右边的位数
小数点的。如果为负数,则
数字的未标度值为
乘以10,等于
量表的否定。量表的值
由
因此,BigDecimal是(非标度值
×10标度)
scale
可以通过设置。我不确定这在一般情况下是否可行。例如,1.0e-13
有多少个小数位?如果它是由于做算术时的舍入错误造成的,实际上只是伪装成了0
。如果是,另一方面,你会问是否有任何非零位在第一个n小数位中,您可以执行以下操作:
static boolean checkDecimalPlaces(double d, unsigned int decimalPlaces){
// take advantage of truncation, may need to use BigInt here
// depending on your range
double d_abs = Math.abs(d);
unsigned long d_i = d_abs;
unsigned long e = (d_abs - d_i) * Math.pow(10, decimalPlaces);
return e > 0;
}
测试失败,因为您已达到二进制浮点表示法的精度,约为16位。将649632196443.4279乘以10000将截断二进制表示法,导致随后的舍入和除法错误,从而使函数结果完全无效
有关更多详细信息,请参阅
更好的方法是检查n+1
小数位是否低于某个阈值。如果d-四舍五入(d)
小于(请参阅),d
的小数位表示形式没有有效的小数位。同样,如果(d-四舍五入(d))*10^n
小于epsilon
,d最多可以有n
个有效位置
使用“s”检查d
不够精确,无法保留您要查找的小数位数的情况。如果您可以切换到BigDecimal,那么正如Ken G所解释的,这就是您应该使用的
如果不是,那么你必须处理其他答案中提到的一系列问题。对我来说,你处理的是一个二进制数(double)并问一个关于该数字的十进制表示的问题;也就是说,你问的是一个字符串。我认为你的直觉是正确的。我认为这样更好
转换为字符串并查询指数的值
public int calcBase10Exponet (Number increment)
{
//toSting of 0.0=0.0
//toSting of 1.0=1.0
//toSting of 10.0=10.0
//toSting of 100.0=100.0
//toSting of 1000.0=1000.0
//toSting of 10000.0=10000.0
//toSting of 100000.0=100000.0
//toSting of 1000000.0=1000000.0
//toSting of 1.0E7=1.0E7
//toSting of 1.0E8=1.0E8
//toSting of 1.0E9=1.0E9
//toSting of 1.0E10=1.0E10
//toSting of 1.0E11=1.0E11
//toSting of 0.1=0.1
//toSting of 0.01=0.01
//toSting of 0.0010=0.0010 <== need to trim off this extra zero
//toSting of 1.0E-4=1.0E-4
//toSting of 1.0E-5=1.0E-5
//toSting of 1.0E-6=1.0E-6
//toSting of 1.0E-7=1.0E-7
//toSting of 1.0E-8=1.0E-8
//toSting of 1.0E-9=1.0E-9
//toSting of 1.0E-10=1.0E-10
//toSting of 1.0E-11=1.0E-11
double dbl = increment.doubleValue ();
String str = Double.toString (dbl);
// System.out.println ("NumberBoxDefaultPatternCalculator: toSting of " + dbl + "=" + str);
if (str.contains ("E"))
{
return Integer.parseInt (str.substring (str.indexOf ("E") + 1));
}
if (str.endsWith (".0"))
{
return str.length () - 3;
}
while (str.endsWith ("0"))
{
str = str.substring (0, str.length () - 1);
}
return - (str.length () - str.indexOf (".") - 1);
}
public int calcBase10Exponet(数字增量)
{
//抛掷0.0=0.0
//抛掷1.0=1.0
//抛掷10.0=10.0
//抛掷100.0=100.0
//抛掷1000.0=1000.0
//抛掷10000.0=10000.0
//抛掷100000.0=100000.0
//抛掷1000000.0=1000000.0
//抛掷1.0E7=1.0E7
//抛掷1.0E8=1.0E8
//抛掷1.0E9=1.0E9
//抛掷1.0E10=1.0E10
//抛掷1.0E11=1.0E11
//抛掷0.1=0.1
//抛掷0.01=0.01
//投掷0.0010=0.0010也许会有帮助。这是我的方法
private int checkPrecisionOfDouble(Double atribute) {
String s = String.valueOf(atribute);
String[] split = s.split("\\.");
return split[1].length();
}
或
当您这样做时,最大的问题是溢出:check=d*multiplier;这不适用于大数字;IEE 754 64位double的精度仅为18位左右,因此,如果您进入的数字乘以1000将导致溢出(约10^304),您可以确定表示中有零位小数。“正确”这里没有什么意义。你的随机十进制数没有精确的二进制表示。你正在寻找一个“足够接近”的十进制数所以人们喜欢十进制版本的二进制值。有多接近才算足够?实际上你的答案帮助了我,但现在它是有缺陷的,因为你必须在截断它之前乘以d
,以避免丢失有效数字-参见我对问题的编辑我还查看了Jon在回答中发布的Double Converter,它似乎是to做的和BigDecimal差不多。我想知道他为什么删除他的答案。
private int checkPrecisionOfDouble(Double atribute) {
String s = String.valueOf(atribute);
String[] split = s.split("\\.");
return split[1].length();
}
private boolean checkPrecisionOfDouble(Double atribute, int decimalPlaces) {
String s = String.valueOf(atribute);
String[] split = s.split("\\.");
return split[1].length() == decimalPlaces;
}