5

I have some abstract double interval, defining by step f.e.:

0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 - where interval == 0.1

0.0, 0.25, 0.5, 0.75, 1.0 - where interval == 0.25

0.0, 0.5, 1.0 - where interval == 0.5

Does Java have some instrument to "round" some double to closest number, according to interval? f.e:

0.511111 - to 0.5 in first case

0.599999 - to 0.6 in first case

0.511111 - to 0.5 in second case

0.599999 - to 0.5 in second case

0.711111 - to 0.75 in second case

0.744444 - to 0.5 in third case

0.755555 - to 1.0 in third case

0.92222 - to 1.0 in third case

2 Answers2

6

Java has instruments which can round numbers to n decimal places, see How to round a number to n decimal places in Java. For rounding to any interval you specified, you may have to manually use Math.round.

Formula:

Given an interval r and a double value x to round, a simple formula is:

  • x_rounded = Math.round(x/r)*r;

Examples:

double x = 0.59999;
double r = 0.25; // Quarters
x = Math.round(x/r)*r;
System.out.println(x); // Result is 0.5

double x = 0.59999;
double r = 0.1; // Tenths
x = Math.round(x/r)*r;
System.out.println(x); // Result is approximately 0.6

double x = 0.31421;
double r = 0.125; // Eighths
x = Math.round(x/r)*r;
System.out.println(x); // Result is exactly 0.375

Proof:

  • The interval r can be thought as the value of a fractional unit.
    • When r = 0.25, the fractional unit is a quarter.
  • The value x/r represents the number of fractional units that make up x.
    • When x = 0.75, r = 0.25, x/r == 3, because x contains three fractional unit, which is the quarter. x/r represents the number of quarters.
  • Math.round(x) rounds x to the nearest integral value. Similarly, Math.round(x/r) rounds x/r to the nearest integral multiple of that fraction.
    • For x = 0.7, r = 0.25, we have x/r = 2.8, representing 2.8 quarters. Math.round(x/r) therefore rounds the value to the nearest quarter, 3 quarters.
  • Math.round(x/r)*r therefore rounds x to the nearest fractional interval r. The multiplier is needed because r is the value of each fractional unit.
    • For x = 0.7, r = 0.25, Math.round(x/r) represents 3 quarters. It has to be multiplied by r=0.25 to get the rounded value of x.
1

Use BigDecimal and setScale() to round.

However it will not work with the 0.25 precision, but you might do a workaround, something like this:

public BigDecimal round( BigDecimal value, BigDecimal precision )
{
   return value.divide(precision, BigDecimal.ROUND_HALF_UP)
               .round(BigDecimal.ROUND_HALF_UP)
               .multiply(precision, BigDecimal.ROUND_HALF_UP);
}
Usagi Miyamoto
  • 5,721
  • 1
  • 16
  • 28