Java中Double类型变量的小数点位数是多少?

11

在Java中是否有内置函数可以告诉我一个double类型变量有多少小数位。例如:

101.13 = 2
101.130 = 3
1.100 = 3
1.1 = 1
-3.2322 = 4 etc.

如果需要的话,我很乐意先转换为另一种类型,我已经尝试过先将其转换为BigDecimal,但没有成功。

7个回答

15

如果你像这样使用字符串形式的数字,你可以使用BigDecimal.scale():

BigDecimal a = new BigDecimal("1.31");
System.out.println(a.scale()); //prints 2
BigDecimal b = new BigDecimal("1.310");
System.out.println(b.scale()); //prints 3

但如果您已经将数字作为字符串,最好使用正则表达式解析该字符串以查看有多少位数字:

String[] s = "1.31".split("\\.");
System.out.println(s[s.length - 1].length());

使用BigDecimal可能具有优点,它可以检查字符串是否实际上是一个数字;使用字符串方法,您必须自己进行检查。而且,如果您将数字作为双精度数,则无法区分1.311.310(它们是完全相同的双精度数),正如其他人也指出的那样。


10

不。

100和1.1在计算机中被表示为相同的位,因此它们代表了完全相同的值(在双精度浮点数 double 中)。

所以你永远无法从一个 double 中获取那种信息。

你唯一能做的是获取将一个十进制数解析为相同 double 值所需的最小十进制数字数。这可以通过调用 Double.toString() 并检查有多少十进制数字来轻松完成。


1
调用 toString() 看起来有点不稳定,但这是我的最初想法。 - Karl
1
@Karl:虽然不太稳定,但这可能是你能做的最好的事情。它在非常大和非常小的值时会出错(因为你会得到科学计数法)。唯一100%正确的解决方案是在将值转换为“double”之前,将其作为“String”进行测试(就像Andrei所演示的那样)。 - Joachim Sauer

8

2
不,那是十进制位数,而且是错误的,应该是15.9。考虑“123456789012345”。十五个十进制位数,零个小数位。“12345678901234.5”。十五个十进制位数,一个小数位。等等。 - user207421
5
我认为15.9是“大约16”。从你的评论中可以看出,你似乎不认为15.9是“大约16”。如果你想宣称15.9不是“大约16”,那么也是错误的,因为它不是15.9。维基百科上写着“十七位十进制数”和15.955个数字。 - S.Lott
6
请仔细阅读IEEE标准,特别是关于尾数中的隐式位的部分。 - S.Lott
3
好的,我们只是在吹毛求疵,但它是15.9545897701910000。保留16位小数;-) - user207421
2
@EJP:不,我们没有争论。你的最初评论很清楚。“大约16是错误的”。然后你声称是15.9,这同样是错误的。你似乎并不在挑剔。你似乎有重要的话要说,而且你已经重复了四次。这不是挑剔。你有一些重要的东西要添加到这个答案中。关于16与15.955相差甚远。 - S.Lott
显示剩余3条评论

4

不,我不知道有内置的函数可以实现这个功能。

不过,有一种简单的方法可以做到。Double.toString会给你一个包含双精度浮点数中所有有效十进制数字的字符串。以下是该字符串的一些属性:

  • 结果可能是十进制表示法或科学计数法,具体取决于双精度浮点数的值。
  • 转换为十进制表示法的双精度浮点数大于或等于10,000,000或小于1/1000,结果为科学计数法。否则,它们是十进制表示法。

使用Double.toString来确定有多少位小数实质上包括小数点右侧的有效数字减去科学计数法指数(如果有)。十进制表示法始终至少有一个数字在小数点右侧,并且至少有一个数字在小数点左侧,即使它是零。由于我们关心的是有效数字的小数位数,因此小数点右侧的尾随零是一个问题,不应被计算为小数位。

以下代码将为您进行良好的计算:

    StringBuffer stringBuffer = new StringBuffer(Double.toString(1234.567890D));
    System.out.println(stringBuffer.toString());
    int i; // general purpose character index
    int exponent;
    int decimalPlaces;
    if ((i = stringBuffer.indexOf("E")) > -1) { // scientific notation...
        // turn scientific notation exponent into an integer
        exponent = Integer.parseInt(stringBuffer.substring(i + 1));
        // truncate the exponent from the StringBuffer
        stringBuffer = stringBuffer.delete(i, stringBuffer.length());
    } else { // decimal notation, could be trailing zero
        exponent = 0; // no exponent, so zero
        // point i to trailing zero and truncate it, if there is one
        if (stringBuffer.charAt((i = stringBuffer.length() - 1)) == '0') {
            stringBuffer = stringBuffer.deleteCharAt(i); // delete trailing zero
        }
    }
    // stringBuffer now contains only significant digits to the
    // right of the decimal point, if there are any
    decimalPlaces = stringBuffer.length() - 1 - stringBuffer.indexOf(".") - exponent;
    // zero or positive number is decimal places
    // negative number is number of zeroes to the left of the decimal point
    // between the decimal point and the least significant digit
    System.out.println(decimalPlaces);

我对所提出的问题有一些疑问。双精度浮点数的小数表示需要什么样的精度?是否不适当地使用双精度浮点数进行十进制计算?使用浮点数和双精度浮点数进行十进制分数计算可能会产生16或17个有效数字的结果,这些结果可能只是等效十进制计算的近似值。
浮点数、双精度浮点数和长双精度浮点数(也称为四倍精度)的一个方面似乎困扰了程序员和设计师,即所有这些格式实际上都存储为二进制小数,除了非常少量的数字外,它们只能近似表示十进制数字,其中大多数数字都相当接近于值1、-1和零值。当从1向正无穷或0进发,或从-1向负无穷或0进发时,近似值的稀疏性将变得明显。
几乎所有的十进制分数在浮点数和双精度浮点数中都没有直接表示。只有由以下系列分数之和组成的某些组合的十进制分数具有精确表示:
1、1/2、1/4、1/8、1/16、1/32、1/64、1/128、1/256、...、1/4503599627370496
其余所有分数都是近似值。
大于+9007199254740992或小于-9007199254740992的整数可能没有精确表示,随着整数从正值或负值以下增加,稀疏性呈指数级增加。
另一种看待这个问题的方法是意识到IEEE 64位双精度浮点数(规范化)近似于绝对值范围从2.225073858507201400 E -308到1.797693134862315700 E +308的正负十进制数字。然而,只有1.8446744073709551616 E +19个值可用于这些近似值。这意味着约有1.0 E +607个十进制值与某些更接近双精度浮点数的其他十进制值共享表示。
浮点数和双精度浮点数的行为会对需要精确十进制精度的十进制计算(例如财务计算)造成影响,因此,除非可以接受高精度近似值,否则应使用缩放整数和长整数,或使用BigInteger和BigDecimal等类来进行需要精确十进制精度、舍入和精度的计算。

3
// ****************************************************************
public int getDecimals(double doubleValue) {
// ****************************************************************
    BigDecimal bd1 = new BigDecimal(Double.toString(doubleValue)).stripTrailingZeros();
    return bd1.scale();
}

toString 部分非常关键。 - David I.

1
很多年前,我记得有一个16位数字的答案,包括小数点前后的数字。我写了一小段代码来测试它。
public class test {
    public static void main(String[] args) {
        double x;`enter code here`
        x = 3411.999999999999;
        System.out.println("16: "+x);   // gives 3411.999999999999
        x = 3411.9999999999999;
        System.out.println("17: "+x);   // gives 3412.0
        x = 0.9999999999999999;
        System.out.println("16: "+x);   // gives 0.9999999999999999
        x = 0.99999999999999999;
        System.out.println("17: "+x);   // gives 1.0
    }  
}

这里有16位数字,计算结果为3411.999999999999。

现在在小数点后面再加一个9,总共17位数字,即3411.9999999999999,重新运行。打印出的值为3412.0。在这种情况下,我们超载了x的内部表示,并且数字被舍入以存储。

println忠实地打印它内部看到的内容。只有64位来保存双精度浮点数(尾数和指数——请参阅IEEE 754了解详细信息)。

玩弄x的值,您将看到效果。例如,0.9999999999999999(16个9)输出0.9999999999999999;0.99999999999999999(17个9)输出1.0。

希望这能帮到您。


-1
StringBuffer stringBuffer = new StringBuffer(Double.toString(ratioGrossYield));
int i; // general purpose character index
int exponent;
int decimalPlaces;
if ((i = stringBuffer.indexOf("E")) > -1) { // scientific notation...
    // turn scientific notation exponent into an integer
    exponent = Integer.parseInt(stringBuffer.substring(i + 1));
    // truncate the exponent from the StringBuffer
    stringBuffer = stringBuffer.delete(i, stringBuffer.length());
} else { // decimal notation, could be trailing zero
    exponent = 0; // no exponent, so zero
    // point i to trailing zero and truncate it, if there is one
    if (stringBuffer.charAt((i = stringBuffer.length() - 1)) == '0') {
        stringBuffer = stringBuffer.deleteCharAt(i); // delete trailing zero
    }
}
// stringBuffer now contains only significant digits to the
// right of the decimal point, if there are any
decimalPlaces = stringBuffer.length() - 1 - stringBuffer.indexOf(".") - exponent;
// zero or positive number is decimal places
// negative number is number of zeroes to the left of the decimal point
// between the decimal point and the least significant digit
if (stringBuffer.charAt(stringBuffer.length() - 1) == '0') {

    return decimalPlaces-1;

} else {

    return decimalPlaces;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接