Skip to main content

finance_solution/
round.rs

1//! **Utilities for rounding** money amounts to the nearest hundredth or ten-thousandth part.
2//!
3//! `assert_rounded_*` helpers are intended for **tests and doctests** (they `assert!` on
4//! non-finite inputs). Production code should prefer comparing with [`round_4`] / [`round_6`]
5//! or structured [`crate::FinanceError`] handling rather than assert-based helpers.
6
7/// Round to two decimal places. This function uses f64::round() which rounds halfway cases away
8/// from 0.0.
9pub fn round_2(val: f64) -> f64 {
10    (val * 100.0).round() / 100.0
11}
12
13/// Round to four decimal places. This function uses f64::round() which rounds halfway cases away
14/// from 0.0.
15pub fn round_4(val: f64) -> f64 {
16    (val * 10_000.0).round() / 10_000.0
17}
18
19/// Round to six decimal places. This function uses f64::round() which rounds halfway cases away
20/// from 0.0.
21pub fn round_6(val: f64) -> f64 {
22    (val * 1_000_000.0).round() / 1_000_000.0
23}
24
25/// Round to eight decimal places. This function uses f64::round() which rounds halfway cases away
26/// from 0.0.
27pub fn round_8(val: f64) -> f64 {
28    (val * 100_000_000.0).round() / 100_000_000.0
29}
30
31#[inline(always)]
32pub fn assert_rounded_2(val_1: f64, val_2: f64) {
33    assert!(val_1.is_finite());
34    assert!(val_2.is_finite());
35    assert_eq!(round_2(val_1), round_2(val_2));
36}
37
38#[inline(always)]
39pub fn assert_rounded_4(val_1: f64, val_2: f64) {
40    assert!(val_1.is_finite());
41    assert!(val_2.is_finite());
42    assert_eq!(round_4(val_1), round_4(val_2));
43}
44
45#[inline(always)]
46pub fn assert_rounded_6(val_1: f64, val_2: f64) {
47    assert!(val_1.is_finite());
48    assert!(val_2.is_finite());
49    assert_eq!(round_6(val_1), round_6(val_2));
50}
51
52#[inline(always)]
53pub fn assert_rounded_8(val_1: f64, val_2: f64) {
54    assert!(val_1.is_finite());
55    assert!(val_2.is_finite());
56    assert_eq!(round_8(val_1), round_8(val_2));
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::*;
63
64    #[test]
65    fn test_equals_zero() {
66        assert_eq!(0.0f64, 0.0f64);
67        assert_eq!(-0.0f64, -0.0f64);
68        assert_eq!(0.0f64, -0.0f64);
69    }
70
71    #[test]
72    fn test_round_2() {
73        assert_eq!(295_489.94, round_2(295_489.941849));
74        assert_eq!(295_489.94, round_2(295_489.9449));
75        assert_ne!(295_489.94, round_2(295_489.9451234));
76    }
77
78    #[test]
79    fn test_round_4() {
80        assert_eq!(295_489.9418, round_4(295_489.941849));
81        assert_eq!(295_489.9418, round_4(295_489.94175));
82        assert_ne!(295_489.9418, round_4(295_489.94185));
83    }
84
85    #[test]
86    fn test_round_6() {
87        assert_eq!(295_489.941849, round_6(295_489.9418494449));
88        assert_eq!(295_489.533367, round_6(295_489.5333669999999));
89        assert_eq!(295_489.945123, round_6(295_489.9451229999));
90        assert_ne!(295_489.945123, round_6(295_489.9451249999));
91    }
92
93    #[test]
94    fn test_round_8() {
95        assert_eq!(295_489.94184944, round_8(295_489.9418494449));
96        assert_eq!(295_489.53336700, round_8(295_489.5333669999999));
97        assert_eq!(295_489.94512333, round_8(295_489.945123329999));
98        assert_ne!(295_489.94512333, round_8(295_489.9451249999));
99    }
100
101    #[test]
102    fn test_assert_rounded_2_nominal() {
103        assert_rounded_2!(53_243.7448, 53_243.7401);
104    }
105
106    #[test]
107    #[should_panic]
108    fn test_assert_rounded_2_panic() {
109        assert_rounded_2!(53_243.7458, 53_243.7401);
110    }
111
112    /*
113    #[test]
114    fn test_assert_approx_equal() {
115        assert_approx_equal!(53_243.7448, 53_243.7401);
116    }
117    */
118
119    #[test]
120    #[should_panic]
121    fn test_assert_approx_equal_panic() {
122        assert_rounded_2!(53_243.8123, 53_243.7401);
123    }
124}