Java - rounding double to 2 decimal places - java

I know this question has been asked many times but I'm stuck and I don't know what the correct solution should be. I'm writing a program and there's a lot of numbers multiplication. The result must be rounded to 2 decimal places but sometimes the result is not correct.
For example:
I have two doubles v1=99.338 and v2=732.5.
I want to multiply them and have the result rounded to 2 decimal places.
The correct result is 72765.085 so after rounding it should be 72765.09 however in computer the result is 72765.08499999999 and all the rounding methods give 72765.08 which is obviously wrong.
For example
double x= v1 * v2; //x=72765.08499999999
DecimalFormat dec= new DecimalFormat("0.00");
decsetRoundingMode(RoundingMode.HALF_UP);
String v = dec.format(x);
gives 72765.08. The RoundingMode.CEILING in this example works OK but with other values for v and v2 is wrong.
NumberFormat nf= NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
nf.format(x);
gives 72765.08.
BigDecimal big = new BigDecimal(x, setScale(2, RoundingMode.HALF_UP);
double v = decWartosc.format(x);
gives v=72765.08.
Any other ideas?
I've tried this in C# and the result is correct.

You must use BigDecimal for the calculation itself.
BigDecimal exact = BigDecimal.valueOf(v1).multiply(BigDecimal.valueOf(v2));
BigDecimal big = exact.setScale(2, RoundingMode.HALF_UP);
System.out.println(big.toString());

First of all 99.337 * 732.5 = 72764.3525, and NOT 72765.085.
Now, this code:
BigDecimal b1 = new BigDecimal("99.337");
BigDecimal b2 = new BigDecimal("732.5");
BigDecimal result = b1.multiply(b2).setScale(2, RoundingMode.HALF_UP);
System.out.println(result);
Outputs:
72764.35

Related

Format Java double with only 2 decimal places without rounding

I have variables that are doubles and I want to get the double with only 2 numbers after the decimal point. I tried it with
System.out.printf("%1.2f", number1);
but the decimal places get rounded. For example if I have number1 = 19.867, I just want to get 19.86 and not the rounded version 19.87. How can I do that?
You can use DecimalFormat with an apropriate pattern and a RoundingMode to specify rounding behavior:
double number1 = 19.867;
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(number1));
The same can be achieved by converting the double value to BigDecimal and use BigDecimal‘s setScale() method with a RoundingMode
BigDecimal bigDecimalNumber1 = new BigDecimal(number1).setScale(2, RoundingMode.DOWN);
System.out.println(bigDecimalNumber1.doubleValue());

How to get from 10.0/3*3 BigDecimal and double?

double a = 10.0;
double b =3;
double c = a/b;
System.out.println(c*b);//answer = 10.0
BigDecimal bigDecimal1 = BigDecimal.valueOf(c);
BigDecimal bigDecimal2 = new BigDecimal("3");
System.out.println(bigDecimal1.multiply(bigDecimal2));//answer = 10.0000000000000005
I'm trying to make a calculator, but there's a problem with 10/3*3
I don't want to just calculate 10/3*3 this formula, I want to return this formula plus 0.2323232323232 of the float. So use the BigDecimal class. There's something wrong with it
I couldn't get the exact result, that's what I wanted 10,
Rather than get 10.0000000000000005
I believe your problem may be here
double c = a/b;
...
BigDecimal bigDecimal1 = BigDecimal.valueOf(c);
You're expecting that a double can perfectly represent 10/3, and I doubt it can
Maybe try something like this, which always represents numbers as BigDecimal
new BigDecimal("10").divide(new BigDecimal("3"))
At which point you'll notice that 10/3 is not representable as a decimal
Non-terminating decimal expansion; no exact representable decimal result
You need to decide how much precision you want, and then use rounding
new BigDecimal("10")
.setScale(10)
.divide(new BigDecimal("3"), BigDecimal.ROUND_HALF_EVEN)
Or you could use a rational number library, as suggested by Patricia. Perhaps see Is there a commonly used rational numbers library in Java?

How do you reduce a java double to n significant digits?

I am looking to print small digits (doubles) for the purpose of printing the errors in using the Newton & Secant methods.
One of my errors is 5.433306166802499E-5
I'd like to print 5.4333E-5
I thought of using BigDecimal but I am not familiar with this class.
I am looking to print small digits (doubles)
System.out.printf("%.4e", 5.433306166802499E-5);
Result: 5.4333e-05
Note: it doesn't reduce the precision of your original value, it just prints it with a lower precision.
double d = 5.433306166802499E-5;
BigDecimal dc = new BigDecimal(d);
dc = dc .round(new MathContext(3)); // desired significant digits
double rounded = dc .doubleValue();
You can indeed use BigDecimal, it would then look as follows:
BigDecimal d = BigDecimal.valueOf(val).setScale(scale, RoundingMode.HALF_UP);
double scaled = d.doubleValue();
Or you could use:
Math.round(val*Math.pow(10, scale))/Math.pow(10, scale);
To answer the general question of reducing a double's significant digits, and not just the case of printing with System.out.printf:
If you're using Java: Double.parseDouble(String.format("%1.4e", 5.433306166802499E-5))
In Scala, you can use the f string interpolator, or the format method:
val a: Double = 5.433306166802499E-5
val reduced1: Double = f"$a%1.4e".toDouble
val reduced2: Double = "%1.4e".format(a).toDouble
Both are equal: 5.4333e-05

How to always round off upto 2 decimal places in java

I have tried the following code but it is not working in a particular case.
Eg: Suppose, I have a double value=2.5045 and i want it to be rounded off upto two decimal places using the below code.After rounding off, i get the answer as 2.5. But I want the answer to be 2.50 instead. In this case,zero is trimmed off. Is there any way to retain the zero so as to get the desired answer as 2.50 after rounding off.
private static DecimalFormat twoDForm = new DecimalFormat("#.##");
public static double roundTwoDecimals(double amount) {
return Double.valueOf(twoDForm.format(amount));
}
try this pattern
new DecimalFormat("0.00");
but this will change only formatting, double cannot hold number of digits after decimal poin, try BigDecimal
BigDecimal bd = new BigDecimal(2.5045).setScale(2, RoundingMode.HALF_UP);
Look at the documentation for DecimalFormat. For # it says:
Digit, zero shows as absent
0 is probably what you want:
Digit
So what you are looking for is either "0.00" or "#.00" as a format string, depending on whether you want the first digit before the period, to be visible in case the numbers absolute value is smalle than 0.
Try this
DecimalFormat format = new DecimalFormat("#");
format.setMinimumFractionDigits(2);
answer.setText(format.format(data2));
Try This
double d = 4.85999999999;
long l = (int)Math.round(d * 100); // truncates
d = l / 100.0;
You are returning a double. But double or Double are objects representing a number and don't carry any formatting information. Ìf you need to output two decimal places the point to do this is when you convert your double to a String.
use # if you want to ignore 0
new DecimalFormat("###,#0.00").format(d)
There is another way to achieve this . I have already posted answer in post
will just answer again here. As we will require rounding off values many times .
public class RoundingNumbers {
public static void main(String args[]){
double number = 2.5045;
int decimalsToConsider = 2;
BigDecimal bigDecimal = new BigDecimal(number);
BigDecimal roundedWithScale = bigDecimal.setScale(decimalsToConsider, BigDecimal.ROUND_HALF_UP);
System.out.println("Rounded value with setting scale = "+roundedWithScale);
bigDecimal = new BigDecimal(number);
BigDecimal roundedValueWithDivideLogic = bigDecimal.divide(BigDecimal.ONE,decimalsToConsider,BigDecimal.ROUND_HALF_UP);
System.out.println("Rounded value with Dividing by one = "+roundedValueWithDivideLogic);
}
}
Output we will get is
Rounded value with setting scale = 2.50
Rounded value with Dividing by one = 2.50
double kilobytes = 1205.6358;
double newKB = Math.round(kilobytes*100.0)/100.0;
DecimalFormat df = new DecimalFormat("###.##");
System.out.println("kilobytes (DecimalFormat) : " + df.format(kilobytes));
Try this if u are still getting the above problem

Converting numeric value with currency symbol back to Decimal with NumberFormat

I would like to convert a possibly Decimal value prefixed with currency symbol into only numeric value.
For example -
The value can be like any of the following
String s1 = "£32,847,676.65";
String s2 = "£3,456.00";
String s3 = "£831,209";
I would like the result after conversion to be like - 32847676.65, 3456.00 and 831209.
I tried using the parse() method of the NumberFormat in this way -
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.UK);
numberFormat.setMinimumFractionDigits(2);
Number num = nf.parse(s1);
double dd = num.doubleValue();
BigDecimal gg = new BigDecimal(dd);
System.out.println(gg);
But the result is - 32847676.649999998509883880615234375 which is not quite exactly the correct one.
I need it to be numeric so that may be I can perform some kind of calculation.
Can you guys guide me with what else can I try
You already parse the value correctly. The problem is this:
BigDecimal gg = new BigDecimal(dd);
You covnert the value to BigDecimal, and the rounding problems of doubles account for the decimal places after the dot. Use:
BigDecimal gg = new BigDecimal(dd).setScale(2);
or
BigDecimal gg = new BigDecimal(dd).setScale(2,RoundingMode.HALF_UP);
When playing with BigDecimal, the appropriate constructor is BigDecimal(String val)
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.UK);
BigDecimal gg = new BigDecimal(nf.parse(s1).toString());
System.out.println(gg);
BigDecimal(double val) does construct an exact decimal representation of the double value, which is not the human readable value you expected.
"The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
[...]
Therefore, it is generally recommended that the String constructor be used in preference to this one"
Source : BigDecimal javadoc
You can try the following without BigDecimal or NumberFormat. ;)
String s1 = "£32,847,676.65";
// remove the £ and ,
String s2 = s1.replaceAll("[£,]", "");
// then turn into a double
double d = Double.parseDouble(s2);
// and round up to two decimal places.
double value = (long) (d * 100 + 0.5) / 100.0;
System.out.printf("%.2f%n", value);
prints
32847676.65
If youw ant to avoid rounding error in your calculations but don't want the heavy weight BigDecimal you can use long cents.
// value in cents as an integer.
long value = (long) (d * 100 + 0.5);
// perform some calculations on value here
System.out.printf("%.2f%n", value / 100.0);
It is not guaranteed to work, but according to the NumberFormat API documentation, its getXyzInstance methods will return a DecimalFormat instance for "the vast majority of locales". This can probably be interpreted as "for all locales, unless proprietary locale service providers are installed".
If you can cast your NumberFormat to DecimalFormat, you can tell it to parse to a BigDecimal directly, reducing your code to:
DecimalFormat nf = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.UK);
nf.setParseBigDecimal(true);
BigDecimal gg = (BigDecimal) nf.parse(s1);
System.out.println(gg);
In this case, you will have no problem with the inaccuracy of binary floating point numbers.

Categories

Resources