简体   繁体   中英

Truncating Double to 2 decimal places?

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?

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, ie BigDecimal or DecimalFormat .

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 (eg 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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM