How many decimal Places in A Double (Java)
Asked Answered
E

7

11

Is there any in built function in java to tell me how many decimal places in a double. For example:

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

I am happy to convert to another type first if needed, I have looked at converting to bigdecimal first with no luck.

Ernieernst answered 26/7, 2010 at 10:57 Comment(0)
R
10

No.

1.100 and 1.1 are exactly the same value (they are represented exactly the same bit-for-bit in a double).

Therefore you can't ever get that kind of information from a double.

The only thing you can do is to get the minimum number of decimal digits necessary for a decimal number to be parsed into the same double value. And that is as easy as calling Double.toString() and checking how many decimal digits there are.

Rotate answered 26/7, 2010 at 11:0 Comment(2)
Calling toString() seems a little shakey but was my initial thought.Ernieernst
@Karl: it is shaky, but possibly the best thing you can do. It breaks for very large and very small values (as you'll get scientific notation). The only 100% correct solution is to do that test when you have the value as a String before you convert it to a double (as Andrei demonstrates).Rotate
K
15

You could use BigDecimal.scale() if you pass the number as a String like this:

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

but if you already have the number as string you might as well just parse the string with a regex to see how many digits there are:

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

Using BigDecimal might have the advantage that it checks if the string is actually a number; using the string method you have to do it yourself. Also, if you have the numbers as double you can't differentiate between 1.31 and 1.310 (they're exactly the same double) like others have pointed out as well.

Kew answered 26/7, 2010 at 11:7 Comment(0)
R
10

No.

1.100 and 1.1 are exactly the same value (they are represented exactly the same bit-for-bit in a double).

Therefore you can't ever get that kind of information from a double.

The only thing you can do is to get the minimum number of decimal digits necessary for a decimal number to be parsed into the same double value. And that is as easy as calling Double.toString() and checking how many decimal digits there are.

Rotate answered 26/7, 2010 at 11:0 Comment(2)
Calling toString() seems a little shakey but was my initial thought.Ernieernst
@Karl: it is shaky, but possibly the best thing you can do. It breaks for very large and very small values (as you'll get scientific notation). The only 100% correct solution is to do that test when you have the value as a String before you convert it to a double (as Andrei demonstrates).Rotate
O
8

The number of decimal places in a double is 16.

64-bit numbers. 52-bit Mantissa. 52 bits is about 16 decimal digits.

See http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html.

double, whose values include the 64-bit IEEE 754 floating-point numbers.

See http://en.wikipedia.org/wiki/IEEE_754-2008

Obtuse answered 26/7, 2010 at 11:0 Comment(8)
No, that's the number of decimal digits, and it's wrong, it is 15.9. Consider "123456789012345". Fifteen decimal digits, zero decimal places. "12345678901234.5". Fifteen decimal digits, one decimal place. Etc.Blacklist
@EJP: I would think that 15.9 is "About 16". It appears from your comment that you don't think 15.9 is "about 16". If you want to claim 15.9 is not "about 16", then you're wrong also, since it's not 15.9, either. Wikipedia says "17 decimal digits" and 15.955 digits.Obtuse
Then both you and Wikipedia are wrong. When it comes to decimal digits, 15.9 is about 15, because you can't rely on the 16th digit being there. And it certainly isn't 17.Blacklist
@EJP: Please read the IEEE standard carefully. In particular, read about the implicit bits in the significand.Obtuse
There are 53 bits of mantissa. That's 53 binary digits, which in turn is 15.9 decimal digits. Some of the time you get 16; most ofmthe time don't. If you are implementing to a precision of 16 decimal digits, 15.9 isn't enough.Blacklist
OK, we are just quibbling here, but it is 15.9545897701910000. To 16 decimal places ;-)Blacklist
@EJP: No. We're not quibbling. Your initial comment was clear. "about 16 is wrong". And then you claimed it was 15.9 which is equally wrong. You don't appear to he quibbling. You appear to have something important to say and you've repeated that something important now four separate times. That's not quibbling. You've got something important to add to this answer. Something about 16 being not even close to 15.955.Obtuse
Perhaps you could provide the relevant formula: decimal digits = digit bits * log10(base) and point to the table here.Kattie
V
4

No, there is no built-in function that I know about.

There is a simple way to do this, though. Double.toString will give you a string containing ALL significant decimal digits in the double. The following are some properties of that string:

  • The String that results may be in decimal notation or scientific notation, depending on the value of the double.
  • Doubles that convert to decimals 10,000,000 or larger or smaller than 1/1000 result in scientific notation. Otherwise, they are in decimal notation.

Using Double.toString to figure out how many decimal places there are essentially comprises how many significant digits to the right of the decimal point minus a scientific notation exponent, if there is one. Decimal notation will always have at least one digit to the right of the decimal point, and at least one digit to the left of the decimal point, even if it is a zero. Since we are concerned about decimal places for significant digits, a trailing zero to the right of the decimal point is a concern and should not be counted as a decimal place.

The following code will make a good calculation for you:

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

I have some questions about the question posed. What kind of precision is expected with the decimal representation of a double? Are doubles being used to inappropriately perform decimal computations? Decimal computations with decimal fractions using floats and doubles can have results that unexpectedly have 16 or 17 significant digits and may be only approximations of the expected results from equivalent decimal computations.

One aspect of float, doubles, long doubles (aka quads) that seems to stymie programmers and designers is that all these formats are actually stored as binary fractional numbers that can only approximate decimal numbers except for a very, very few numbers, most of which are fairly close to the values 1, -1, plus the value zero. As one progresses towards positive infinity or zero from 1, or towards negative infinity or zero from -1, the sparseness of the approximation will become apparent.

Almost all decimal fractions have no direct representation in floats and doubles. Only decimal fractions that can be comprised from the sum of some combination of the following series of fractions have an exact representation:

1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, ..., 1/4503599627370496

All the rest are approximations.

Integers greater than +9007199254740992 or less than -9007199254740992 may not have an exact representation and the sparseness increases exponentially as integers increase above the positive or decrease below the negative values, respectively.

Another way to look at this is to realize that IEEE 64-bit doubles, normalized, approximate positive and negative decimal numbers having absolute values ranging from 2.225073858507201400 E -308 through 1.797693134862315700 E +308. However, there are only 1.8446744073709551616 E +19 values available for these approximations. That means about 1.0 E +607 decimal values share a representation with some other decimal values that are more closely approximated by a double.

The behavior of floats and doubles wrecks havoc with decimal computations requiring exact decimal accuracy, such as financial calculations and is why, unless a high-precision approximation is acceptable, one should use scaled integers and longs, or classes such as BigInteger and BigDecimal, for computations requiring exact decimal accuracy, rounding and precision.

Vonnie answered 11/7, 2012 at 2:10 Comment(0)
S
3
// ****************************************************************
public int getDecimals(double doubleValue) {
// ****************************************************************
    BigDecimal bd1 = new BigDecimal(Double.toString(doubleValue)).stripTrailingZeros();
    return bd1.scale();
}
Shavonneshaw answered 28/11, 2012 at 13:10 Comment(1)
The toString part is crucial.Onassis
S
1

From many long years ago, I recall an answer of 16 digits, total of before and after the decimal point.

I wrote a tiny bit of code to test that.

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

There 4+12 = 16 digits. A run outputs 3411.999999999999.

Now add one more 9 behind the decimal point for a total of 17 - 3411.9999999999999 - and rerun. The value printed is 3412.0. In this case, we overload the internal representation of x, and the number is rounded internally to store.

The println faithfully prints what it sees internally. There are only so many bits - 64 to be exact - to hold the double floating number (significand and exponent - see IEEE 754 for the gory details).

Play around with the value of x and you'll see the effects. For instance, 0.9999999999999999 (16 9s)give output 0.9999999999999999; 0.99999999999999999 (17 9s) gives 1.0.

Hope this helps.

Stilly answered 3/6, 2013 at 17:37 Comment(0)
C
-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;
}
Connective answered 23/4, 2013 at 6:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.