123

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?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
vgonisanz
  • 11,831
  • 13
  • 78
  • 130
  • 4
    You can take a look at this question: http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java – Jave Jan 18 '12 at 14:00
  • 1
    or you could find the number after the decimal, cast it to int, and right bit shift. Basically what round would do. – L7ColWinters Jan 18 '12 at 14:03

7 Answers7

177

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
xarlymg89
  • 2,552
  • 2
  • 27
  • 41
Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
  • 2
    But 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 – vgonisanz Jan 18 '12 at 14:36
  • 1
    How would you round to 2 decimal places in Android? – marienke Jun 20 '13 at 13:45
  • I like to keep it short `new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);` – azerafati Jul 30 '14 at 07:28
  • 2
    I 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. – hamham May 26 '16 at 08:56
  • Yes, probably it is the best answer, but 4 years later, I think the guy who asked does not need that anymore :) – Jav_Rock Jun 01 '16 at 19:43
  • What does this rounding function look like if it accepted a BigDecimal as the argument instead of a float or double? – fIwJlxSzApHEZIl May 30 '17 at 17:44
  • 1
    Use bd.setScale(decimalPlace, RoundingMode.UP); instead of bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); --> latter is deprecated – Blackpanther0001 Jul 16 '18 at 11:25
58

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

manikanta
  • 8,100
  • 5
  • 59
  • 66
Ivan Stin
  • 715
  • 5
  • 6
  • The **second** one does not work for negative numbers. E.g. `round(-10.26f, 1)` returns -10.2 rather than -10.3. – Lym Zoy Aug 18 '17 at 00:57
  • 1
    @LymZoy I've fixed the -ve numbers issue. See my answer https://stackoverflow.com/a/45772416/340290 – manikanta Aug 19 '17 at 13:57
  • 1
    Why 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; }` – gil.fernandes Jan 16 '18 at 19:21
  • @gil.fernandes, good note – Ivan Stin Jan 18 '18 at 16:38
35
double roundTwoDecimals(double d) {
  DecimalFormat twoDForm = new DecimalFormat("#.##");
  return Double.valueOf(twoDForm.format(d));
}
Shadow
  • 6,161
  • 3
  • 20
  • 14
16

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
JaskeyLam
  • 15,405
  • 21
  • 114
  • 149
10

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);
}
manikanta
  • 8,100
  • 5
  • 59
  • 66
4

Here is a simple one-line solution

((int) ((value + 0.005f) * 100)) / 100f
Ilya Bystrov
  • 2,902
  • 2
  • 14
  • 21
  • As @IvanStin tested this is the fastest and the best instant solution. Thank you! – Abigail La'Fay Jun 05 '19 at 21:56
  • 2
    does 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; – Sergio Mar 29 '20 at 11:29
-5
//by importing Decimal format we can do...

import java.util.Scanner;
import java.text.DecimalFormat;
public class Average
{
public static void main(String[] args)
{
int sub1,sub2,sub3,total;
Scanner in = new Scanner(System.in);
System.out.print("Enter Subject 1 Marks : ");
sub1 = in.nextInt();
System.out.print("Enter Subject 2 Marks : ");
sub2 = in.nextInt();
System.out.print("Enter Subject 3 Marks : ");
sub3 = in.nextInt();
total = sub1 + sub2 + sub3;
System.out.println("Total Marks of Subjects = " + total);
res = (float)total;
average = res/3;
System.out.println("Before Rounding Decimal.. Average = " +average +"%");
DecimalFormat df = new DecimalFormat("###.##");
System.out.println("After Rounding Decimal.. Average = " +df.format(average)+"%");
}
}
/* Output
Enter Subject 1 Marks : 72
Enter Subject 2 Marks : 42
Enter Subject 3 Marks : 52
Total Marks of Subjects = 166
Before Rounding Decimal.. Average = 55.333332%
After Rounding Decimal.. Average = 55.33%
*/

/* Output
Enter Subject 1 Marks : 98
Enter Subject 2 Marks : 88
Enter Subject 3 Marks : 78
Total Marks of Subjects = 264
Before Rounding Decimal.. Average = 88.0%
After Rounding Decimal.. Average = 88%
*/

/* You can Find Avrerage values in two ouputs before rounding average
And After rounding Average..*/
Sandeep16
  • 1
  • 5