Here to Learn.
Here to Learn.

Reputation: 693

Issue in rounding a float to a precision

I am writing a function round: static float round(float number, precision){}

The function should work like this: round(12.3456f, 3) = 12.345

My definition of function is like this:

public static float round(float value, int precision) {
float result;
if(precision <= 0){
    throw new RuntimeException("Precision can not be zero or less");
}

int number = (int) power(10,precision);
value = value * number;
result = (float)Math.round(value)/number;

return result;
} 

But the issue is that, my unit test case for this function doesn't pass,

 public void mathTestNew() {
    assertEquals("MathTest",12.341,OOTBFunctions.round(12.3416f,3));
 }

The result is junit.framework.AssertionFailedError: MathTest expected:<12.341> but was:<12.342>

I am not sure how to overcome this error. I am not sure if BigDecimal will help me in this.

Upvotes: 3

Views: 1238

Answers (5)

creemama
creemama

Reputation: 6665

If you did want to use BigDecimal:

public static float round(float value, int precision) {
    if (precision <= 0) {
        throw new IllegalArgumentException("Precision cannot be zero or less.");
    }
    BigDecimal decimal = BigDecimal.valueOf(value);
    return decimal.setScale(precision, RoundingMode.FLOOR).floatValue();
}

You may lose accuracy when converting from BigDecimal to float, so if accuracy is a must, do not convert; keep the value as a BigDecimal.

As mentioned in other answers, float is an approximation of a base 10 number. The following demonstrates just that:

System.out.println(BigDecimal.valueOf(12.3416f)); // outputs 12.34160041809082
System.out.println(new BigDecimal("12.3416"));    // outputs 12.3416

Upvotes: 2

mikera
mikera

Reputation: 106401

Rounding normally occurs towards the nearest integer. So 12.3416 is correctly rounded to 12.342

If you want the rounding behaviour you seem to be asking for (where the number is rounded down towards negative infinity) then you should use Math.floor(x) instead of Math.round(x)

Also be careful with rounding floats / doubles as they both suffer from numerical inaccuracy. If you really want high accuracy on decimal places, you may be better using BigDecimal instead.

Upvotes: 4

user207421
user207421

Reputation: 311048

You can't write such a method. Floating point doesn't have decimal places, it has binary places. Ergo you cannot round to a specified number of decimal places. If you want decimmal places you must use a decimal radix, i.e. BigDecimal, or DecimalFormat. Apart from the error in expectation noted by @ColeJohnson, code like you have written will fail in over 90% of cases.

Upvotes: 0

Cole Tobin
Cole Tobin

Reputation: 9425

12.3416 rounded is 12.342. There in lies your problem. You probably want Math.Floor instead. I would recomend against constantly multiplying as that can ruin the number. However, by 10 does not lower precision.

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272772

Math.round is "round-to-nearest". You probably want Math.floor.

Upvotes: 3

Related Questions