4

I know this question is repeated alot, but please have a look at the statement first than mark it already answered :)

For truncating the double values 2 decimal places I use two ways which are mostly mentioned everywhere. They are given below

    //this one
    DecimalFormat dtime = new DecimalFormat("#.##"); 
    return Double.valueOf(dtime.format(val));
    //or the one below
    BigDecimal bd = new BigDecimal(val);
    BigDecimal rounded = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
    return rounded.doubleValue();

The problem is that for both the ways I mostly get correct rounded values in the dataset. But strangely at the same time I get values like 2.00000000000005 or 19.97999999999.

The problem that I dont get is that why only a few values are not rounded of. What could be wrong?

Aneeque
  • 99
  • 1
  • 9
  • 1
    possible duplicate of [Floating point inaccuracies](http://stackoverflow.com/questions/4575643/floating-point-inaccuracies) – Ingo Apr 04 '13 at 18:31
  • 1
    Voted to close: you did not understand the answers to te other 5786 questions about double/float precision. Go back, and read again. – Ingo Apr 04 '13 at 18:32
  • Do you get “values like” 2.00000000000005, or do you get 2.00000000000005? If you get 19.9800000000000004, for example, this is likely caused by converting a rounded value to binary floating point. That conversion causes some error, as explained in other answers. If you get 2.00000000000005, then there is some other problem, because a value that has been rounded to 2.00 will stay 2 when converted to floating point. In the latter, case Ingo has improperly voted to close this as a duplicate. – Eric Postpischil Apr 04 '13 at 18:39
  • like this value.. i meant the number of decimal places are not truncated.. sorry for the confusion – Aneeque Apr 04 '13 at 18:43
  • i flagged for closing myself.. thnx – Aneeque Apr 04 '13 at 18:48
  • 1
    please where is @EJP with his Double has not decimal places ... :-) – mKorbel Apr 04 '13 at 19:14
  • Why on earth was this reopened? ***Definite*** duplicate of http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java and hundreds of others. – user207421 Sep 29 '13 at 20:27

4 Answers4

2

For truncating the double values 2 decimal places I use two ways which are mostly mentioned everywhere.

And they are both wrong, because they are attempting the impossible. There is no such thing as truncating a double to 2 decimal places, because doubles don't have decimal places. They have binary places. See my answer here for proof. If you want decimal places you have to use a decimal radix, i.e. BigDecimal or DecimalFormat.

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

Issue is that floating point numbers are inherently approximate in nature, given the underlying representation. Therefore you will want to use them in places where approximations are good, and avoid them where approximations are no good (e.g. financials).

The call to rounded.doubleValue() still returns a floating point number and so it is still impacted by the limitations of the representation.

See

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

for more information.

  • like this value.. i meant the number of decimal places are not truncated.. sorry for the confusion – Aneeque Apr 04 '13 at 18:43
  • Understood. The floating point representation has no built-in precision. When you "truncate" the number, you are just zeroing out a certain part of the number, and then displaying whatever is left over. If it turns out that the intended number has no exact floating point representation, then you will be stuck with the best that the representation can offer, which will be numbers similar to the ones you've offered. E.g. if there is no exact floating point representation for 19.98 (to use your example), then you'll have to deal with whatever representation is "close enough". –  Apr 04 '13 at 19:45
  • thnx for the clear answer :). Any way to get over this issue apart from truncating as a String? – Aneeque Apr 04 '13 at 20:28
  • Sure. Multiply by 100 and use integers. Kind of like the difference between dealing in dollars and pennies. –  Apr 04 '13 at 20:55
  • 2
    It's not correct to say 'the floating point representation has no built-in precision'. It does, represented by the exponent and the number of non-zero fraction bits. The point is that they are *bits,* not decimal digits, so you can't express the precision as an integral number of decimal digits. – user207421 Apr 05 '13 at 00:06
  • Thanks EJP for the clarification. Makes sense. –  Apr 05 '13 at 00:26
0

The following piece of code helped me in restricting the number of decimal places (truncating) for a double value.

public static Double truncate (double valueToTruncate, int numberOfDecimalPlaces) {

    if (valueToTruncate > 0) {
        return new BigDecimal(String.valueOf(valueToTruncate)).setScale(numberOfDecimalPlaces, BigDecimal.ROUND_FLOOR).doubleValue();
    } else {
        return new BigDecimal(String.valueOf(valueToTruncate)).setScale(numberOfDecimalPlaces, BigDecimal.ROUND_CEILING).doubleValue();
    }
}

Hope this helps someone :)

Madhu Tomy
  • 662
  • 11
  • 25
-1

I'm new to this but keeping everything in front of me I did it this way. Now mind you this is a truncation mathematically, I don't convert to string except in my debugs after each line.

It isn't elegant but seems to work. This is purely a problem solving framework.

Anyway;

import java.util.Scanner;
public class TestConstructs 
 {
private static double w;
private static int w1;
private static double w2;
private static double w3;
private static int w4;
private static double w5;
private static double w6;

public static void main(String[] args) 
{
    // TODO Auto-generated method stub
    TestConstructs foo = new TestConstructs();
    foo.setWage(w);

}

public void setWage(double w)
{

    Scanner input = new Scanner(System.in);
    System.out.println("Enter Wage: "); //enter something longish like 30987.978654 or w/e
    w = input.nextDouble();
    w1 = (int)w;
    System.out.printf("%d w1\n",w1);
    w2 = w - w1;
    System.out.printf("%.3f w2\n",w2);
    w3 = w2*100;
    System.out.printf("%.3f w3\n",w3);
    w4 = (int)w3;
    System.out.printf("%d w4\n",w4);
    w5 = (double)w4;
    System.out.printf("%.3f w5\n",w5);
    w6 = 0 + w5/100;
    System.out.printf("%.3f w6\n",w6);
    w = w1 + w6;

    System.out.printf("%.3f final value\n",w); //.3 to show zero 
    input.close();
}

}

What I got at the end Enter Wage: 30987.978654 30987 w1 0.979 w2 97.865 w3 97 w4 97.000 w5 0.970 w6 30987.970 final value

Daff
  • 1
  • 1
  • It doesn't work. See my answer in http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java for proof. – user207421 Sep 29 '13 at 20:29
  • While doing it your way does ROUND up for this project I had to TRUNCATE to two decimal places not ROUND. Additionally in the course I'm taking I can't using the method you are using it beyond the course scope. – Daff Sep 29 '13 at 22:02
  • On another note I know that doubles are not bound to places so there is no absolute truncate without a string conversion. The purpose of this was to drop as much numerical garbage beyond the second decimal place as possible, nothing in double is exactly precise but using what I wrote effectively destroysd the consideration of the integer at position .00(x) which was what I needed. – Daff Sep 29 '13 at 22:07
  • Rounding isn't implied by anything I have said. Using a decimal radix only rounds up if you do so. There is no absolute truncation to *n* decimal places without a conversion to *decimal radix.* Strings have nothing to do with it. Either this method truncates to a fixed number of decimal places or it doesn't, and it doesn't. It can't. – user207421 Sep 30 '13 at 00:30