Java rounding Issue - java

I have a case, such that, if the float value is 74.126, it is rounded into 74.13 ie. into 2 decimal places. But if the value is 74.125, it should be rounded into 74.12...
Please help me to achieve this kind of rounding methodology
Thanks in advance.

I suggest you use BigDecimal instead of float, as that's a more natural representation where decimal digits make sense.
However, I don't think you actually want the round method, as that deals with precision instead of scale. I think you want setScale, as demonstrated here:
import java.math.*;
public class Test {
public static void main(String[] args) {
roundTo2DP("74.126");
roundTo2DP("74.125");
}
private static void roundTo2DP(String text) {
BigDecimal before = new BigDecimal(text);
BigDecimal after = before.setScale(2, RoundingMode.HALF_DOWN);
System.out.println(after);
}
}

Presumably you are rounding with Math.round(float a)? If so the javadocs explain pretty much how rounding works better than I can here.
You may want to look at the BigDecimal class as it provides a round(MathContext mc) method that allows you to specify different rounding modes such as HALF_DOWN.
Edit:
If you just want to set the number of decimal places you can do it with the setScale method.
float f = 74.125f;
BigDecimal b = new BigDecimal(f).setScale(2, RoundingMode.HALF_DOWN);

Related

Java Display 2 decimal with float variable [duplicate]

I need to format a float to "n"decimal places.
was trying to BigDecimal, but the return value is not correct...
public static float Redondear(float pNumero, int pCantidadDecimales) {
// the function is call with the values Redondear(625.3f, 2)
BigDecimal value = new BigDecimal(pNumero);
value = value.setScale(pCantidadDecimales, RoundingMode.HALF_EVEN); // here the value is correct (625.30)
return value.floatValue(); // but here the values is 625.3
}
I need to return a float value with the number of decimal places that I specify.
I need Float value return not Double
.
You may also pass the float value, and use:
String.format("%.2f", floatValue);
Documentation
Take a look at DecimalFormat. You can easily use it to take a number and give it a set number of decimal places.
Edit: Example
Try this this helped me a lot
BigDecimal roundfinalPrice = new BigDecimal(5652.25622f).setScale(2,BigDecimal.ROUND_HALF_UP);
Result will be
roundfinalPrice --> 5652.26
Of note, use of DecimalFormat constructor is discouraged. The javadoc for this class states:
In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.
https://docs.oracle.com/javase/8/docs/api/java/text/DecimalFormat.html
So what you need to do is (for instance):
NumberFormat formatter = NumberFormat.getInstance(Locale.US);
formatter.setMaximumFractionDigits(2);
formatter.setMinimumFractionDigits(2);
formatter.setRoundingMode(RoundingMode.HALF_UP);
Float formatedFloat = new Float(formatter.format(floatValue));
Here's a quick sample using the DecimalFormat class mentioned by Nick.
float f = 12.345f;
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(f));
The output of the print statement will be 12.35. Notice that it will round it for you.
Kinda surprised nobody's pointed out the direct way to do it, which is easy enough.
double roundToDecimalPlaces(double value, int decimalPlaces)
{
double shift = Math.pow(10,decimalPlaces);
return Math.round(value*shift)/shift;
}
Pretty sure this does not do half-even rounding though.
For what it's worth, half-even rounding is going to be chaotic and unpredictable any time you mix binary-based floating-point values with base-10 arithmetic. I'm pretty sure it cannot be done. The basic problem is that a value like 1.105 cannot be represented exactly in floating point. The floating point value is going to be something like 1.105000000000001, or 1.104999999999999. So any attempt to perform half-even rounding is going trip up on representational encoding errors.
IEEE floating point implementations will do half-rounding, but they do binary half-rounding, not decimal half-rounding. So you're probably ok
public static double roundToDouble(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
}
This is a much less professional and much more expensive way but it should be easier to understand and more helpful for beginners.
public static float roundFloat(float F, int roundTo){
String num = "#########.";
for (int count = 0; count < roundTo; count++){
num += "0";
}
DecimalFormat df = new DecimalFormat(num);
df.setRoundingMode(RoundingMode.HALF_UP);
String S = df.format(F);
F = Float.parseFloat(S);
return F;
}
I was looking for an answer to this question and later I developed a method! :) A fair warning, it's rounding up the value.
private float limitDigits(float number) {
return Float.valueOf(String.format(Locale.getDefault(), "%.2f", number));
}
I think what you want ist
return value.toString();
and use the return value to display.
value.floatValue();
will always return 625.3 because its mainly used to calculate something.
You can use Decimal format if you want to format number into a string, for example:
String a = "123455";
System.out.println(new
DecimalFormat(".0").format(Float.valueOf(a)));
The output of this code will be:
123455.0
You can add more zeros to the decimal format, depends on the output that you want.

Java BigDecimal - explanation needed

I was using BigDecimal, but I am still getting different results for two different (mathematically identical) expressions:
First Expression: PI - (10^(-14)/PI)
Second Expression: (PI^2 - 10^(-14))/PI
To put it more simply, here is the equation:
package set1;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class FloatingLaws {
final static BigDecimal PI = BigDecimal.valueOf(Math.PI);
public static void main(String[] args) {
System.out.println(firstExpression());
System.out.println(secondExpression());
}
private static BigDecimal secondExpression() {
return PI.subtract((BigDecimal.valueOf(Math.pow(10, -14)).divide(PI,50,RoundingMode.CEILING)));
}
private static BigDecimal firstExpression() {
return (PI.multiply(PI).subtract(BigDecimal.valueOf(Math.pow(10, -14)))).divide(PI, 50,RoundingMode.CEILING);
}
}
After executing this code, no matter how big is rounding, last digit is always different. In my case I get these two results:
3.14159265358978981690113816209304300915191180404867
3.14159265358978981690113816209304300915191180404866
My question is why is this happening and is it solvable?
It is because You are doing this:
pi - ((10^-4)/pi)<- only the part in bracket is ceiled,
which is different from
((pi^2-10^-14)/pi)<- where the whole expression is ceiled.
You use BigDecimal and you have rounding mode CEILING with precision 50. In both of your expressions the ceiling is applied when you divide by PI number. So if you divide by PI eager like in first expression, then you could get less accurate results - because you CEIL intermediate value, before your formula fully execute, so you loose the CEILED part from the divide by PI operation and this in further computation creates the "error" effect.
When you divide by PI last, like in second expression, you use more accurate formula, which is ceiling only the result, not intermediate value like in first expression, so it calculates more preciselly, rounding only the result and not intermediate value.
The BigDecimal.subtract method always produces exact difference between two BigDecimal numbers, without rounding. On the other hand BigDecimal.divide usually rounds the result. In your case you are use CEILING rounding mode which rounds up (towards +infinity). When you calculate a-ceil(b/a), you are essentially rounding down the whole result (assuming that a is already rounded), while calculating ceil((a*a-b)/a) you're rounding up. That's why firstExpression() is bigger. Were you using HALF_EVEN rounding, the result would be the same. Were you using FLOOR mode, the result would be opposite.
Also take a look to what is BigDecimal.valueOf(Math.PI);:
System.out.println(BigDecimal.valueOf(Math.PI));
> 3.141592653589793
It's not even close to the actual PI number (given the fact that you need 50 digits). You should define PI explicitly like this:
final static BigDecimal PI = new BigDecimal("3.14159265358979323846264338327950288419716939937510");
Now the result is the following:
3.14159265358979005536378154537278750652190194908786
3.14159265358979005536378154537278750652190194908785
Which is quite different from yours one.
I modified your program to try all rounding modes java knows.
Running under oracle jdk 8.72, i get equal results for the rounding modes HALF_UP, HALF_DOWN and HALF_EVEN. But Krzysztof is right, since you are not rounding in the same places, errors are bound to pop up.
public class FloatingLaws {
final static BigDecimal PI = BigDecimal.valueOf(Math.PI);
public static void main(String[] args) {
for (RoundingMode roundingMode : RoundingMode.values()) {
System.out.println(roundingMode);
System.out.println("Equal? "+firstExpression(roundingMode).equals(secondExpression(roundingMode)));
System.out.println(firstExpression(roundingMode));
System.out.println(secondExpression(roundingMode));
}
}
private static BigDecimal secondExpression(RoundingMode roundingMode) {
return PI.subtract((BigDecimal.valueOf(Math.pow(10, -14)).divide(PI, 50, roundingMode)));
}
private static BigDecimal firstExpression(RoundingMode roundingMode) {
return (PI.multiply(PI).subtract(BigDecimal.valueOf(Math.pow(10, -14)))).divide(PI, 50, roundingMode);
}
}

Fix for float precision issue without BigDecimal

I'm having an issue with the rounding of a float value.
The following code gives me the following result:
public class ProductOrder {
public static void main(String[] args) {
int q = 48;
float p = 6.95f;
System.out.println(q * p);
}
------
Output: 333.59998
While the expected result should be 333.6
When I replace q with 49 then its okay and i get 340,55
As already pointed out, BigDecimal is designed for situations in which exact handling of short decimal fractions is especially important, and is much better for those situations than any binary floating point format.
The second best solution is to work in e.g. integer number of cents, and insert the decimal point only during display.
If you must use binary floating point, double is usually a better choice than float unless you are dealing with a lot of numbers and know float has enough precision.
For output, if you expect a result with e.g. no more than 2 decimal digits after the decimal point, you can use a DecimalFormat to round accordingly:
import java.text.DecimalFormat;
public class Test {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("#0.##");
int q = 48;
float p = 6.95f;
System.out.println(df.format(q * p));
}
}
prints 333.6
The default formatting produces the least number of digits that are necessary to tell the number from from its neighbours. This means that if the result is even slightly off because of roundoff error you will get the "ugly" output.
One way to deal with this is using exact arithmetic (BigDecimal or integer arithmetic). Another is rounding the output, for example:
System.out.printf("%f", p*q);
The number 333.6 is not representable exactly as a float, which has up to 6 decimal digits precision. When you tried to print it with too much precision (8 digits) the underlying rounding error was revealed.
double has up to 15 digits precision.
However, as others have pointed out, if you are dealing with financial calculations you should work in BigDecimal.
For reference you can use the IEEE-754 Floating-Point Conversion website to see, for any given decimal number, exactly how it is represented in float and double.
The issue here is that floating points are subject to floating point precision errors. You can use double for twice the precision (you will still eventually get errors, but it is more accurate than using float).
E.g.
public static void main(String[] args) {
int q = 48;
double p = 6.95;
System.out.println(q * p);
}
This will give 333.6.

Android - exact mathematical calculation

I have got a Problem, I am developing an Application which should be able to do some mathematic calculations. These calculations have to be exact (or rather not obviously wrong)
But this simple Code
double a = 3.048d;
double b = 1000d;
double c = a / b;
gives me a wrong result c is not 0.003048 as expected instead it is 0.0030480000000000004 which is obviously wrong.
double d = 3.048 / 1000;
this second code-snipet gives the correct result.
I am aware that all floatingpoint arithmetic is not exact when calculating with computers but I don't know how to solve this problem.
thanks in advance!
Ludwig
Developing for:
- Android 2.2
Testdevice:
- HTC Desire
What you need to use for exact percision is the BigDecimal object:
BigDecimal a = new BigDecimal("3.048");
BigDecimal b = new BigDecimal(1000);
BigDecimal c = a.divide(b);
System.out.println(c); //0.003048
This is a consequence of the IEEE 754 floating point representation, not an error. To deal with it, round your result to an appropriate precision.
Use a BigDecimal for precise floating point calculations. Setting the scale allows you to specify precisely how far out you want to go for output.
import java.math.BigDecimal;
class Test{
public static void main(String[] args){
BigDecimal a = new BigDecimal("3.048");
BigDecimal b = new BigDecimal(1000);
BigDecimal c = a.divide(b).setScale(6);
System.out.println(c); //0.003048
}
}
Use BigDecimal for such precise allocations.
Btw the result for d is obviously right, because double has a machine encoding which cannot store the result, which you perceive as correct.

Format Float to n decimal places

I need to format a float to "n"decimal places.
was trying to BigDecimal, but the return value is not correct...
public static float Redondear(float pNumero, int pCantidadDecimales) {
// the function is call with the values Redondear(625.3f, 2)
BigDecimal value = new BigDecimal(pNumero);
value = value.setScale(pCantidadDecimales, RoundingMode.HALF_EVEN); // here the value is correct (625.30)
return value.floatValue(); // but here the values is 625.3
}
I need to return a float value with the number of decimal places that I specify.
I need Float value return not Double
.
You may also pass the float value, and use:
String.format("%.2f", floatValue);
Documentation
Take a look at DecimalFormat. You can easily use it to take a number and give it a set number of decimal places.
Edit: Example
Try this this helped me a lot
BigDecimal roundfinalPrice = new BigDecimal(5652.25622f).setScale(2,BigDecimal.ROUND_HALF_UP);
Result will be
roundfinalPrice --> 5652.26
Of note, use of DecimalFormat constructor is discouraged. The javadoc for this class states:
In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.
https://docs.oracle.com/javase/8/docs/api/java/text/DecimalFormat.html
So what you need to do is (for instance):
NumberFormat formatter = NumberFormat.getInstance(Locale.US);
formatter.setMaximumFractionDigits(2);
formatter.setMinimumFractionDigits(2);
formatter.setRoundingMode(RoundingMode.HALF_UP);
Float formatedFloat = new Float(formatter.format(floatValue));
Here's a quick sample using the DecimalFormat class mentioned by Nick.
float f = 12.345f;
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(f));
The output of the print statement will be 12.35. Notice that it will round it for you.
Kinda surprised nobody's pointed out the direct way to do it, which is easy enough.
double roundToDecimalPlaces(double value, int decimalPlaces)
{
double shift = Math.pow(10,decimalPlaces);
return Math.round(value*shift)/shift;
}
Pretty sure this does not do half-even rounding though.
For what it's worth, half-even rounding is going to be chaotic and unpredictable any time you mix binary-based floating-point values with base-10 arithmetic. I'm pretty sure it cannot be done. The basic problem is that a value like 1.105 cannot be represented exactly in floating point. The floating point value is going to be something like 1.105000000000001, or 1.104999999999999. So any attempt to perform half-even rounding is going trip up on representational encoding errors.
IEEE floating point implementations will do half-rounding, but they do binary half-rounding, not decimal half-rounding. So you're probably ok
public static double roundToDouble(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
}
This is a much less professional and much more expensive way but it should be easier to understand and more helpful for beginners.
public static float roundFloat(float F, int roundTo){
String num = "#########.";
for (int count = 0; count < roundTo; count++){
num += "0";
}
DecimalFormat df = new DecimalFormat(num);
df.setRoundingMode(RoundingMode.HALF_UP);
String S = df.format(F);
F = Float.parseFloat(S);
return F;
}
I was looking for an answer to this question and later I developed a method! :) A fair warning, it's rounding up the value.
private float limitDigits(float number) {
return Float.valueOf(String.format(Locale.getDefault(), "%.2f", number));
}
I think what you want ist
return value.toString();
and use the return value to display.
value.floatValue();
will always return 625.3 because its mainly used to calculate something.
You can use Decimal format if you want to format number into a string, for example:
String a = "123455";
System.out.println(new
DecimalFormat(".0").format(Float.valueOf(a)));
The output of this code will be:
123455.0
You can add more zeros to the decimal format, depends on the output that you want.

Categories