What's the best practice to round a float to 2 decimals?
Solution 1
I was working with statistics in Java 2 years ago and I still got the codes of a function that allows you to round a number to the number of decimals that you want. Now you need two, but maybe you would like to try with 3 to compare results, and this function gives you this freedom.
/**
* Round to certain number of decimals
*
* @param d
* @param decimalPlace
* @return
*/
public static float round(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.floatValue();
}
You need to decide if you want to round up or down. In my sample code I am rounding up.
Hope it helps.
EDIT
If you want to preserve the number of decimals when they are zero (I guess it is just for displaying to the user) you just have to change the function type from float to BigDecimal, like this:
public static BigDecimal round(float d, int decimalPlace) {
BigDecimal bd = new BigDecimal(Float.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd;
}
And then call the function this way:
float x = 2.3f;
BigDecimal result;
result=round(x,2);
System.out.println(result);
This will print:
2.30
Solution 2
Let's test 3 methods:
1)
public static double round1(double value, int scale) {
return Math.round(value * Math.pow(10, scale)) / Math.pow(10, scale);
}
2)
public static float round2(float number, int scale) {
int pow = 10;
for (int i = 1; i < scale; i++)
pow *= 10;
float tmp = number * pow;
return ( (float) ( (int) ((tmp - (int) tmp) >= 0.5f ? tmp + 1 : tmp) ) ) / pow;
}
3)
public static float round3(float d, int decimalPlace) {
return BigDecimal.valueOf(d).setScale(decimalPlace, BigDecimal.ROUND_HALF_UP).floatValue();
}
Number is 0.23453f
We'll test 100,000 iterations each method.
Results:
Time 1 - 18 ms
Time 2 - 1 ms
Time 3 - 378 ms
Tested on laptop
Intel i3-3310M CPU 2.4GHz
Solution 3
double roundTwoDecimals(double d) {
DecimalFormat twoDForm = new DecimalFormat("#.##");
return Double.valueOf(twoDForm.format(d));
}
Solution 4
Here is a shorter implementation comparing to @Jav_Rock's
/**
* Round to certain number of decimals
*
* @param d
* @param decimalPlace the numbers of decimals
* @return
*/
public static float round(float d, int decimalPlace) {
return BigDecimal.valueOf(d).setScale(decimalPlace,BigDecimal.ROUND_HALF_UP).floatValue();
}
System.out.println(round(2.345f,2));//two decimal digits, //2.35
Solution 5
I've tried to support the -ve values for @Ivan Stin excellent 2nd method. (Major credit goes to @Ivan Stin for his method)
public static float round(float value, int scale) {
int pow = 10;
for (int i = 1; i < scale; i++) {
pow *= 10;
}
float tmp = value * pow;
float tmpSub = tmp - (int) tmp;
return ( (float) ( (int) (
value >= 0
? (tmpSub >= 0.5f ? tmp + 1 : tmp)
: (tmpSub >= -0.5f ? tmp : tmp - 1)
) ) ) / pow;
// Below will only handles +ve values
// return ( (float) ( (int) ((tmp - (int) tmp) >= 0.5f ? tmp + 1 : tmp) ) ) / pow;
}
Below are the tests cases I've tried. Please let me know if this is not addressing any other cases.
@Test
public void testFloatRound() {
// +ve values
Assert.assertEquals(0F, NumberUtils.round(0F), 0);
Assert.assertEquals(1F, NumberUtils.round(1F), 0);
Assert.assertEquals(23.46F, NumberUtils.round(23.4567F), 0);
Assert.assertEquals(23.45F, NumberUtils.round(23.4547F), 0D);
Assert.assertEquals(1.00F, NumberUtils.round(0.49999999999999994F + 0.5F), 0);
Assert.assertEquals(123.12F, NumberUtils.round(123.123F), 0);
Assert.assertEquals(0.12F, NumberUtils.round(0.123F), 0);
Assert.assertEquals(0.55F, NumberUtils.round(0.55F), 0);
Assert.assertEquals(0.55F, NumberUtils.round(0.554F), 0);
Assert.assertEquals(0.56F, NumberUtils.round(0.556F), 0);
Assert.assertEquals(123.13F, NumberUtils.round(123.126F), 0);
Assert.assertEquals(123.15F, NumberUtils.round(123.15F), 0);
Assert.assertEquals(123.17F, NumberUtils.round(123.1666F), 0);
Assert.assertEquals(123.46F, NumberUtils.round(123.4567F), 0);
Assert.assertEquals(123.87F, NumberUtils.round(123.8711F), 0);
Assert.assertEquals(123.15F, NumberUtils.round(123.15123F), 0);
Assert.assertEquals(123.89F, NumberUtils.round(123.8909F), 0);
Assert.assertEquals(124.00F, NumberUtils.round(123.9999F), 0);
Assert.assertEquals(123.70F, NumberUtils.round(123.7F), 0);
Assert.assertEquals(123.56F, NumberUtils.round(123.555F), 0);
Assert.assertEquals(123.00F, NumberUtils.round(123.00F), 0);
Assert.assertEquals(123.50F, NumberUtils.round(123.50F), 0);
Assert.assertEquals(123.93F, NumberUtils.round(123.93F), 0);
Assert.assertEquals(123.93F, NumberUtils.round(123.9312F), 0);
Assert.assertEquals(123.94F, NumberUtils.round(123.9351F), 0);
Assert.assertEquals(123.94F, NumberUtils.round(123.9350F), 0);
Assert.assertEquals(123.94F, NumberUtils.round(123.93501F), 0);
Assert.assertEquals(99.99F, NumberUtils.round(99.99F), 0);
Assert.assertEquals(100.00F, NumberUtils.round(99.999F), 0);
Assert.assertEquals(100.00F, NumberUtils.round(99.9999F), 0);
// -ve values
Assert.assertEquals(-123.94F, NumberUtils.round(-123.93501F), 0);
Assert.assertEquals(-123.00F, NumberUtils.round(-123.001F), 0);
Assert.assertEquals(-0.94F, NumberUtils.round(-0.93501F), 0);
Assert.assertEquals(-1F, NumberUtils.round(-1F), 0);
Assert.assertEquals(-0.50F, NumberUtils.round(-0.50F), 0);
Assert.assertEquals(-0.55F, NumberUtils.round(-0.55F), 0);
Assert.assertEquals(-0.55F, NumberUtils.round(-0.554F), 0);
Assert.assertEquals(-0.56F, NumberUtils.round(-0.556F), 0);
Assert.assertEquals(-0.12F, NumberUtils.round(-0.1234F), 0);
Assert.assertEquals(-0.12F, NumberUtils.round(-0.123456789F), 0);
Assert.assertEquals(-0.13F, NumberUtils.round(-0.129F), 0);
Assert.assertEquals(-99.99F, NumberUtils.round(-99.99F), 0);
Assert.assertEquals(-100.00F, NumberUtils.round(-99.999F), 0);
Assert.assertEquals(-100.00F, NumberUtils.round(-99.9999F), 0);
}
vgonisanz
Victor Goñi received his M.S. degree in Telecommunication Engeneering from the Public University of Navarra, Pamplona, Spain, in 2010. He spent an internship course at the Monterrey Institute of Technology and Higher Education, Mexico, during 2009, as a complement of his Engineer degree. He wrote his final Master Thesis at Vicomtech-IK4, San Sebastian, Spain, under the title of "Peripheral Evaluation for Virtual Environment Control", which received an A grade. Since then, he is working in the 3D Animation and Interactive Virtual Environments Department of Vicomtech-IK4 as a research assistant. He has developed a deep interest in science, programming and scientific research, especially in algorithm efficiency, real-time complex calculation and optimization. He is also interested in graphic engines and sensor data filtering and processing for electronic devices. He is specialized in code developement on mobile platforms. Also he is interested in resurrect tiranosaurios rex. My goal to achieve is to be a developer/architect that writes C++ like musicians compose music and songs.
Updated on July 17, 2022Comments
-
vgonisanz almost 2 years
I'm using eclipse + Android SDK.
I need to round a float value to 2 decimals. I usually use the next "trick" using Math library.
float accelerometerX = accelerometerX * 100; accelerometerX = round(accelerometerX); Log.d("Test","" + accelerometerX/100);
But I feel it is not the best way to do it.
Is there a library to do these type of operations?
-
Jave over 12 yearsYou can take a look at this question: stackoverflow.com/questions/153724/…
-
L7ColWinters over 12 yearsor you could find the number after the decimal, cast it to int, and right bit shift. Basically what round would do.
-
-
vgonisanz over 12 yearsI'm trying to use that function with float, but throw exceptions
-
vgonisanz over 12 yearsBut now, the float show only 1 decimal if the second is 0. Do you know how to show always sign and all (2) decimals?? Example: 2.1234 --> 2.12 but 2.1 --> 2.1 but no 2.10
-
marienke almost 11 yearsHow would you round to 2 decimal places in Android?
-
akohout over 10 yearsThe method is designed for Doubles. I added the same function for Floats.
-
azerafati almost 10 yearsI like to keep it short
new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);
-
Sandeep16 over 9 yearswe Have to use import java.text.DecimalFormat; other wise it throws Exception...
-
Teepeemm over 9 yearsThis is a lot of extra fluff for what is essentially Shadow's answer of
DecimalFormat.format(double)
. -
Ranjithkumar about 8 yearsthis is working for me.. you need to change like this float roundTwoDecimals(float d) { DecimalFormat twoDForm = new DecimalFormat("#.##"); return Float.valueOf(twoDForm.format(d)); }
-
hamham almost 8 yearsI implemented this in an Android game I am working on, creating a new
BigDecimal
instance multiple times each frame accounted for 99.9% of my memory allocations, so something to watch out for. In my opinion @Evan Stin's method 2 is the best answer, it's faster and doesn't leave anything behind. -
Jav_Rock almost 8 yearsYes, probably it is the best answer, but 4 years later, I think the guy who asked does not need that anymore :)
-
fIwJlxSzApHEZIl almost 7 yearsWhat does this rounding function look like if it accepted a BigDecimal as the argument instead of a float or double?
-
Lym Zoy over 6 yearsThe second one does not work for negative numbers. E.g.
round(-10.26f, 1)
returns -10.2 rather than -10.3. -
manikanta over 6 years@LymZoy I've fixed the -ve numbers issue. See my answer stackoverflow.com/a/45772416/340290
-
gil.fernandes over 6 yearsWhy not use a variable for the powered number in the first example?:
private static double round(double average, int scale) { double pow = Math.pow(10, scale); return Math.round(average * pow) / pow; }
-
Ivan Stin over 6 years@gil.fernandes, good note
-
Blackpanther0001 almost 6 yearsUse bd.setScale(decimalPlace, RoundingMode.UP); instead of bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); --> latter is deprecated
-
Abigail La'Fay almost 5 yearsAs @IvanStin tested this is the fastest and the best instant solution. Thank you!
-
Sergio about 4 yearsdoes not work with negative values. If you want to fix that change the formula to: ((int) ((value + (value >= 0 ? 1 : -1) * 0.005f) * 100)) / 100f;
-
Hasen over 3 years
double d
? Might wanna rethink that.