Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using DecimalFormat to format big double numbers

Tags:

java

I am trying to use DecimalFormat to format double numbers to just print the number with 2 decimal places if it has fractional part else i want to print number as it is. When number is small, below code works fine but with big numbers, It's not working as expected.

    DecimalFormat df = new DecimalFormat("#.##"); //have tried just # too
    double d1 = 56789d;
    System.out.println(df.format(d1)); //works fine - prints 56789

    double d2 = 1234567879123456789d;
    System.out.println(df.format(d2)); // does not work

Second outputs 1234567879123456770 while I want 1234567879123456789. For double values with decimal part, I just want to retain two decimal points.

Any suggestions on what's going wrong?

like image 478
RandomQuestion Avatar asked Feb 25 '14 23:02

RandomQuestion


People also ask

How do you display upto 2 decimal places?

Just use %. 2f as the format specifier. This will make the Java printf format a double to two decimal places. /* Code example to print a double to two decimal places with Java printf */ System.

How do you round double to two DP?

We can use DecimalFormat("0.00") to ensure the number always round to 2 decimal places.

What is 2f in Java?

2f syntax tells Java to return your variable (value) with 2 decimal places (. 2) in decimal representation of a floating-point number (f) from the start of the format specifier (%).

How do I get 2 decimal places in Javascript?

To limit the number of digits up to 2 places after the decimal, the toFixed() method is used. The toFixed() method rounds up the floating-point number up to 2 places after the decimal. Parameters: String: The floating-point number in the string format that is to be parsed.


1 Answers

The explanation as to why the parsed value is off by 19 lies in the how double values are represented, as IEEE floating-point numbers with 53 bits of precision. That is, for large values as you're inputting, the precision is actually greater than 1. The method Math.ulp, for "unit in last place", gives the closest double values can be apart at the magnitude of its argument.

double d2 = 1234567879123456789d;
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(Math.ulp(d2));
System.out.println(df.format(d2));

This outputs

256.0
1234567879123456770

So, you get the closest double value to the number you type in the source code. Section 3.10.2 of the JLS covers double literals:

The elements of the types float and double are those values that can be represented using the IEEE 754 32-bit single-precision and 64-bit double-precision binary floating-point formats, respectively.

The details of proper input conversion from a Unicode string representation of a floating-point number to the internal IEEE 754 binary floating-point representation are described for the methods valueOf of class Float and class Double of the package java.lang.

And referring to Double.valueOf javadocs:

s is regarded as representing an exact decimal value in the usual "computerized scientific notation" or as an exact hexadecimal value; this exact numerical value is then conceptually converted to an "infinitely precise" binary value that is then rounded to type double by the usual round-to-nearest rule of IEEE 754 floating-point arithmetic [...]

Additionally, this value is still within the range of long values, which will still represent the integer value correctly.

long l2 = 1234567879123456789L;
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(l2));

This outputs

1234567879123456789
like image 75
rgettman Avatar answered Sep 28 '22 01:09

rgettman