129

I was working with numbers recently and I had a situation where I want to set the precision of a double value say to 6 digits or 4 digits, depending on the value stored in the database.

For example, If in the database the precision is set as 4 digits then the output must look as,

10.0000.

I tried with DecimalFormat and using the string ##.####, but it is annoying to use symbols everytime.

Is there any better approach, say something like below:

Double value = 10.0;
value.setPrecision(4);
Raptor
  • 53,206
  • 45
  • 230
  • 366
Kiran
  • 1,309
  • 2
  • 9
  • 5

11 Answers11

339

You can try BigDecimal for this purpose

Double toBeTruncated = new Double("3.5789055");

Double truncatedDouble = BigDecimal.valueOf(toBeTruncated)
    .setScale(3, RoundingMode.HALF_UP)
    .doubleValue();
Enigo
  • 3,685
  • 5
  • 29
  • 54
Neel
  • 3,407
  • 2
  • 11
  • 2
  • 14
    Why no one has up voted this answer it's perfect. – user1613360 Nov 06 '14 at 16:57
  • 2
    works well, "new Double" can be removed – halafi Apr 05 '16 at 11:18
  • 1
    will there be lossy conversion when we call doubleValue()? – swapyonubuntu Nov 21 '16 at 05:24
  • 2
    try double r1 = BigDecimal.valueOf(2.945777946674339E8D).setScale(3, RoundingMode.HALF_UP).doubleValue();--- you get 2.94577794667E8. The output looks different from your requirement. – Khanna111 Jan 05 '17 at 22:39
  • This answer doesn't start from a `double` value, which rules it out of court immediately, and it doesn't deliver a correct result in all cases, because it can't. It's impossible. – user207421 Mar 01 '19 at 09:21
  • @halafi No, `new Double(...)` can not be removed. You can't initialize a `Double` from a string literal value. – user207421 Jun 24 '20 at 10:20
  • I had to round 0.5628655927233627 to 0.5 without al the geek stuff of rounding to next nearest, ceiling etc. .setScale(1, RoundingMode.FLOOR) did the trick For more information check https://www.tutorialspoint.com/java/math/bigdecimal_setscale_rm_roundingmode.htm and https://docs.oracle.com/javase/7/docs/api/java/math/RoundingMode.html – veritas Sep 04 '20 at 11:00
  • 1
    @veritas It worked in that specific case, because 0.5 has an exact FP representation. Most fractions don't. – user207421 Mar 22 '21 at 00:16
79

You can't set the precision of a double (or Double) to a specified number of decimal digits, because floating-point values don't have decimal digits. They have binary digits.

You will have to convert into a decimal radix, either via BigDecimal or DecimalFormat, depending on what you want to do with the value later.

See also my answer to this question for a refutation of the inevitable *100/100 answers.

Community
  • 1
  • 1
user207421
  • 305,947
  • 44
  • 307
  • 483
75

This is an easy way to do it:

String formato = String.format("%.2f");

It sets the precision to 2 digits.

If you only want to print, use it this way:

System.out.printf("%.2f",123.234);
Adam Howell
  • 415
  • 1
  • 11
  • 24
  • 3
    just to clarify: `double myDouble = 42.99; String formatted = String.format("%.2f", myDouble);` – jdex Sep 03 '18 at 05:24
  • 2
    This doesn't set the precision to 2 digits. It rounds a number to 2 digits of precision. That is not the same thing. If the number you are rounding in the first place contained the wrong value because of insufficient precision then rounding will not help. – Gili Jul 23 '19 at 02:24
  • @Gili, can u explain the difference between Precision and Rounding? Some example will be more helpfull – Vipresh Sep 30 '21 at 12:10
  • @Vipresh Per https://stackoverflow.com/a/14845954/14731 `double` contains a fixed precision. If you sum `0.1` ten times you will end up with a double that is not strictly equal to `1.0`. This is because floating-point numbers cannot accurately represent all decimal numbers, even ones with a single digit of (decimal) precision. If you invoke `String.format()` on a number that is already imprecise there is no guarantee that the result will be accurate to 2 digits of precision. – Gili Oct 01 '21 at 15:04
27

To set precision for double values DecimalFormat is good technique. To use this class import java.text.DecimalFormat and create object of it for example

double no=12.786;
DecimalFormat dec = new DecimalFormat("#0.00");
System.out.println(dec.format(no));

So it will print two digits after decimal point here it will print 12.79

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
Jay Patel
  • 2,341
  • 2
  • 22
  • 43
11

This worked for me:

public static void main(String[] s) {
        Double d = Math.PI;
        d = Double.parseDouble(String.format("%.3f", d));  // can be required precision
        System.out.println(d);
    }
bretter
  • 441
  • 7
  • 12
4

Here's an efficient way of achieving the result with two caveats.

  1. Limits precision to 'maximum' N digits (not fixed to N digits).
  2. Rounds down the number (not round to nearest).

See sample test cases here.

123.12345678 ==> 123.123
1.230000 ==> 1.23
1.1 ==> 1.1
1 ==> 1.0
0.000 ==> 0.0
0.00 ==> 0.0
0.4 ==> 0.4
0 ==> 0.0
1.4999 ==> 1.499
1.4995 ==> 1.499
1.4994 ==> 1.499

Here's the code. The two caveats I mentioned above can be addressed pretty easily, however, speed mattered more to me than accuracy, so i left it here. String manipulations like System.out.printf("%.2f",123.234); are computationally costly compared to mathematical operations. In my tests, the below code (without the sysout) took 1/30th the time compared to String manipulations.

public double limitPrecision(String dblAsString, int maxDigitsAfterDecimal) {
    int multiplier = (int) Math.pow(10, maxDigitsAfterDecimal);
    double truncated = (double) ((long) ((Double.parseDouble(dblAsString)) * multiplier)) / multiplier;
    System.out.println(dblAsString + " ==> " + truncated);
    return truncated;
}
user207421
  • 305,947
  • 44
  • 307
  • 483
justAnotherGuy
  • 367
  • 4
  • 10
3

The precision of double and float is fixed by their size and the way the IEEE floating point types are implemented.

The number of decimal digits in the output, on the other hand, is a matter of formatting. You are correct that typing the same constant over and over is a bad idea. You should declare a string constant instead, and use its symbolic representation.

private static final String DBL_FMT = "##.####";

Using a symbolic representation would let you change precision in all places the constant is used without searching through your code.

user207421
  • 305,947
  • 44
  • 307
  • 483
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

To expand on @EJP, the concept of 'precision' when dealing with doubles is extremely fraught. As discussed in https://stackoverflow.com/a/3730040/390153 you can't even represent 0.1 as a double regardless of the precision, for the same reason you can't represent 1/3 in base 10 with finite precision.

You need to consider the problem you are trying to solve, and consider:

a) Should I be using doubles in the first place; if precision is a relevant concept, then using doubles may well be a mistake.

b) If doubles are appropriate, what do I mean by precision? If you are only talking about display, wrap the logic in a display function and you will only need to deal with it in one place; ie. apply the DRY principle.

Community
  • 1
  • 1
Recurse
  • 3,557
  • 1
  • 23
  • 36
2
BigDecimal value = new BigDecimal(10.0000);
value.setScale(4);
Kurru
  • 14,180
  • 18
  • 64
  • 84
user2601995
  • 6,463
  • 8
  • 37
  • 41
0
public static String setPrecision(String number, int decimal) {
    double nbr = Double.valueOf(number);
    int integer_Part = (int) nbr;
    double float_Part = nbr - integer_Part;
    int floating_point = (int) (Math.pow(10, decimal) * float_Part);
    String final_nbr = String.valueOf(integer_Part) + "." + String.valueOf(floating_point);
    return final_nbr;
}
Kurru
  • 14,180
  • 18
  • 64
  • 84
ConkerJ
  • 11
-1

Maybe this method would help you for precising double values.

double truncate(double number)
    {
        int integerPart = (int) number;
        double fractionalPart = number - integerPart;
        fractionalPart *= 100;  //It is for upto two decimal values after point.
                                //You can increase the zeros to fulfill your needs.
        int fractPart = (int) fractionalPart;
        fractionalPart = (double) (integerPart) + (double) (fractPart)/100;
        return fractionalPart;
    }

This method will allow to set the precision level.

double truncate(double number, int precision)
{
    double prec = Math.pow(10, precision);
    int integerPart = (int) number;
    double fractionalPart = number - integerPart;
    fractionalPart *= prec;
    int fractPart = (int) fractionalPart;
    fractionalPart = (double) (integerPart) + (double) (fractPart)/prec;
    return fractionalPart;
}