Skip to content

Commit 42e4b85

Browse files
committed
Add round implementation
1 parent dd06e21 commit 42e4b85

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/lib.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,35 @@ impl BigDecimal {
581581
return result;
582582
}
583583

584+
/// Return number rounded to round_digits precision after the decimal point
585+
/// panic if self.digits() > 16
586+
fn round(&self, round_digits: i64) -> BigDecimal {
587+
let (bigint, decimal_part_digits) = self.as_bigint_and_exponent();
588+
let need_to_round_digits = decimal_part_digits - round_digits;
589+
if round_digits >= 0 && need_to_round_digits <= 0 {
590+
return self.clone();
591+
}
592+
593+
let mut number = bigint.to_i64().unwrap();
594+
// avoid -1555 / 10 = -156
595+
if number < 0 {
596+
number = -number;
597+
}
598+
for _ in 0..(need_to_round_digits-1) {
599+
number /= 10;
600+
}
601+
let digit = number % 10;
602+
if digit <= 4 {
603+
self.with_scale(round_digits)
604+
} else {
605+
if bigint.sign() == Sign::Minus {
606+
self.with_scale(round_digits) - BigDecimal::new(BigInt::from(1), round_digits)
607+
} else {
608+
self.with_scale(round_digits) + BigDecimal::new(BigInt::from(1), round_digits)
609+
}
610+
}
611+
}
612+
584613
/// Return true if this number has zero fractional part (is equal
585614
/// to an integer)
586615
///
@@ -2535,6 +2564,33 @@ mod bigdecimal_tests {
25352564
}
25362565
}
25372566

2567+
#[test]
2568+
fn test_round() {
2569+
let test_cases = vec![
2570+
("1.45", 1, "1.5"),
2571+
("1.444445", 1, "1.4"),
2572+
("1.44", 1, "1.4"),
2573+
("0.444", 2, "0.44"),
2574+
("0.0045", 2, "0.00"),
2575+
("-1.555", 2, "-1.56"),
2576+
("-1.555", 99, "-1.555"),
2577+
("5.5", 0, "6"),
2578+
("-1", -1, "0"),
2579+
("5", -1, "10"),
2580+
("44", -1, "40"),
2581+
("44", -99, "0"),
2582+
("1.4499999999", 1, "1.4"),
2583+
("-1.4499999999", 1, "-1.4"),
2584+
("1.449999999", 1, "1.4"),
2585+
("-9999.444455556666", 10, "-9999.4444555567"),
2586+
];
2587+
for &(x, digits, y) in test_cases.iter() {
2588+
let a = BigDecimal::from_str(x).unwrap();
2589+
let b = BigDecimal::from_str(y).unwrap();
2590+
assert_eq!(a.round(digits), b);
2591+
}
2592+
}
2593+
25382594
#[test]
25392595
fn test_is_integer() {
25402596
let true_vals = vec![

0 commit comments

Comments
 (0)