24

Is there a Java Library function which can be used to truncate a number to an arbitrary number of decimal places? For Example.

SomeLibrary.truncate(1.575, 2) = 1.57

Thanks

  • possible duplicate of [Round a double to 2 significant figures after decimal point](http://stackoverflow.com/questions/2808535/round-a-double-to-2-significant-figures-after-decimal-point) – Mr Fooz Sep 06 '12 at 00:30

11 Answers11

31

Try setScale of BigDecimal like so:

public static double round(double d, int decimalPlace) {
    BigDecimal bd = new BigDecimal(d);
    bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
    return bd.doubleValue();
}
raoulsson
  • 14,978
  • 11
  • 44
  • 68
  • 2
    2 comments: the `BigDecimal` has already a constructor taking a `Double`. The OP also doesn't seem want to round it half up, but just to truncate (floor) it. – BalusC Dec 29 '09 at 21:13
  • Actually, BalusC is right, I want to truncate the value however, your answer set me off in the right direction so I'm accepting it. –  Jan 07 '10 at 21:42
  • 1
    you need to set the RoundingMode to BigDecimal.ROUND_DOWN instead of ROUND_HALF_UP to really truncate a value – zhujik Jul 05 '13 at 13:04
  • improved version of this http://stackoverflow.com/questions/7747469/how-can-i-truncate-a-double-to-only-two-decimal-places-in-java/21468258#21468258 with positive and negative value and not rounding – Mani Jan 30 '14 at 22:15
15

Incredible no one brought this up yet, Java API has had DecimalFormat for ages now for this exact purpose.

Grumdrig
  • 16,588
  • 14
  • 58
  • 69
Esko
  • 29,022
  • 11
  • 55
  • 82
  • 3
    Concretely for the given example the code would look something like this: final DecimalFormat df = new DecimalFormat(); df.setMaximumFractionDigits(2); df.format(1.575); The last expression returns a String which has to be converted back to a double. – ubuntudroid Jun 13 '12 at 15:35
  • This will do round, i think the question to truncate not round. – Mani Jan 30 '14 at 22:08
6

For most numbers, you won't be able to get an exact representation of xxx.yyyy unless you use a decimal class with guaranteed accuracy, such as BigDecimal.

Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
6

There's one in commons-math. Check out http://commons.apache.org/math/apidocs/org/apache/commons/math/util/MathUtils.html:

public static double round(double x,
                           int scale)

It's implemented using BigDecimal, and is overloaded to allow specifying a rounding method, so you can use it to truncate, like this:

org.apache.commons.math.util.MathUtils.round(1.575, 2, 
    java.math.BigDecimal.ROUND_DOWN);

Update:

In the last version (Math3), this method is in the class Precision. org.apache.commons.math3.util.Precision.round(double x, int scale, int roundingMethod)

Thirler
  • 20,239
  • 14
  • 63
  • 92
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
5

Simply remove the fractional portion

public double trunk(double value){ return value - value % 1; }

Edgard Leal
  • 2,592
  • 26
  • 30
2

I just want to add to ubuntudroid's solution. I tried it and it wouldn't round down, so I had to add

df.setRoundingMode(RoundingMode.FLOOR);

for it to work.

dvsaura
  • 21
  • 2
2

here is a short implementation which is many times faster than using BigDecimal or Math.pow

private static long TENS[] = new long[19];
static {
    TENS[0] = 1;
    for (int i = 1; i < TENS.length; i++) TENS[i] = 10 * TENS[i - 1];
}

public static double round(double v, int precision) {
    assert precision >= 0 && precision < TENS.length;
    double unscaled = v * TENS[precision];
    if(unscaled < Long.MIN_VALUE || unscaled > Long.MAX_VALUE) 
       return v;
    long unscaledLong = (long) (unscaled + (v < 0 ? -0.5 : 0.5));
    return (double) unscaledLong / TENS[precision];
}

Delete the assert'ions to taste. ;)

user207421
  • 305,947
  • 44
  • 307
  • 483
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • The only problem I see with this is that you are multiplying parameter `v` by (potentially) several powers of 10, which can cause an overflow. Sure, double max value is around 10^308 so most people won't notice this, however it is possible, which is surprising behaviour (you don't expect a rounding function to have an overflow when submitting a valid value). – RokL Apr 13 '12 at 09:55
  • Just noticed the method will fail as soon as unscaled value will exceed `long` type, which is way sooner. This could be pretty fast even if parameter `v` is small if enough precision is requested. – RokL Apr 13 '12 at 09:58
  • @UMad Ok, changed the check which should handle both cases. – Peter Lawrey Apr 13 '12 at 10:13
  • 1
    round(9.625, 2) returns 9.63 which is wrong as per the question. the answer should be 9.62 – Mani Jan 30 '14 at 22:11
  • @mani good point, if you just want to truncate you can drop the + 0.5 – Peter Lawrey Jan 30 '14 at 22:15
  • 1
    @PeterLawrey dropping +0.5 will not work for round(9.62,2) to 9.61 . the problem is double doesn't has actual decimal point you have to use the BigDecimal or should add extra conditions – Mani Jan 30 '14 at 22:23
2

Use this simple function

double truncateDouble(double number, int numDigits) {
    double result = number;
    String arg = "" + number;
    int idx = arg.indexOf('.');
    if (idx!=-1) {
        if (arg.length() > idx+numDigits) {
            arg = arg.substring(0,idx+numDigits+1);
            result  = Double.parseDouble(arg);
        }
    }
    return result ;
}
0

To do it 100% reliably, you'd have to pass the argument as string, not as floating-point number. When given as string, the code is easy to write. The reason for this is that

double x = 1.1;

does not mean that x will actually evaluate to 1.1, only to the closest exactly representable number.

quant_dev
  • 6,181
  • 1
  • 34
  • 57
0

Actually, this sort of thing is easy to write:

public static double truncate(double value, int places) {
    double multiplier = Math.pow(10, places);
    return Math.floor(multiplier * value) / multiplier;
}

Note that it's Math.floor, because Math.round wouldn't be truncating.

Oh, and this returns a double, because that's what most functions in the Math class return (like Math.pow and Math.floor).

Caveat: Doubles suck for accuracy. One of the BigDecimal solutions should be considered first.

Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • 2
    Note: pow is a very expensive function. Use it if performance is not an issue. – Peter Lawrey Dec 29 '09 at 21:46
  • I like this solution for simplicity and clarity. – David Carboni Jul 14 '12 at 11:29
  • @Mani (well, applies to what EJP said too): I'll note that the Caveat is there for a reason. – Powerlord Jul 20 '14 at 14:46
  • @Powerlord The objective is to truncate a double to an arbitrary number of decimal places, and any solution should do exactly that. This code does not and cannot do it, not because of 'accuracy' but because binary fractions and decimal fractions are incommensurable. – user207421 Jun 10 '15 at 00:50
-1

created a method to do it.

public double roundDouble(double d, int places) {
    return Math.round(d * Math.pow(10, (double) places)) / Math.pow(10, (double)places);
}
Berek Bryan
  • 13,755
  • 10
  • 32
  • 43