Round BigDecimal В зависимости от значения десятого места
Допустим, у меня есть BigDecimal, который может быть любым количеством значений. Если значение на десятом месте меньше 3 (то есть 12,2, я хочу округлить до 12). Если значение десятого места больше или равно 3 (то есть 11,3), я хочу округлить десятое значение до 5 (так что значение здесь в конечном итоге будет 11,5). Имеет ли BigDecimal существующую функциональность, которая позволила бы легко реализовать это. Если нет, то каковы хорошие способы добиться этого в противном случае?
2 ответа
Вы можете сначала масштабировать BigDecimal
до 10 десятичных цифр, используя setScale()
, Затем вы можете манипулировать последней цифрой unscaledValue()
:
public class BigDecimalRounder
{
public static BigDecimal roundToNearestHalf(BigDecimal value)
{
// Scale to 10 decimal digits and get the underlying BigInteger:
BigInteger digits = value.setScale(10, BigDecimal.ROUND_HALF_UP).unscaledValue();
// Act upon the last digit of the BigInteger:
BigInteger lastDigit = digits.mod(BigInteger.TEN);
int intDigit = lastDigit.intValue();
BigInteger newDigit;
if (intDigit >= 0 && intDigit <= 2)
newDigit = BigInteger.ZERO; // round down
else if (intDigit >= 3 && intDigit <= 7)
newDigit = BigInteger.valueOf(5); // round to nearest 5
else
newDigit = BigInteger.TEN; // round up
// Assemble a new BigInteger, removing the original last digit and
// adding the new one (either 0, 5 or 10)
BigInteger newValue = digits.subtract(lastDigit).add(newDigit);
//Assemble a new BigDecimal with the modified digits.
return new BigDecimal(newValue, 10);
}
public static void main(String[] args)
{
BigDecimal mainValue = new BigDecimal("1.2399997990");
BigDecimal addend = BigDecimal.ONE.movePointLeft(10);
for (int i = 1; i <= 12; i++)
{
System.out.println("" + mainValue + " --> " + roundToNearestHalf(mainValue));
mainValue = mainValue.add(addend);
}
}
}
Выход:
1.2399997990 --> 1.2399997990
1.2399997991 --> 1.2399997990
1.2399997992 --> 1.2399997990
1.2399997993 --> 1.2399997995
1.2399997994 --> 1.2399997995
1.2399997995 --> 1.2399997995
1.2399997996 --> 1.2399997995
1.2399997997 --> 1.2399997995
1.2399997998 --> 1.2399998000
1.2399997999 --> 1.2399998000
1.2399998000 --> 1.2399998000
1.2399998001 --> 1.2399998000
Вы можете создать свою собственную версию BigDecimal и переопределить round
метод, но это поможет только при использовании этого метода. Для округления, которое он выполняет естественным образом (при выполнении обычной математики), нет простого способа изменить его поведение округления по сравнению с тем, что он уже предлагает. Если вы посмотрите на реализацию BigDecimal, многие из методов, которые выполняют округление, являются статическими, поэтому вы не сможете их переопределить.
Ниже описано, как вы можете переопределить round
метод.
class MyDecimal extends BigDecimal {
public MyDecimal(BigInteger val) {
super(val);
}
@Override
public BigDecimal round(MathContext mc) {
/* implement your rounding algorithm here*/
}
}