Skip to main content

fixed_bigint/fixeduint/
midpoint_impl.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Midpoint (average) implementation for FixedUInt.
16
17use super::{FixedUInt, MachineWord};
18use crate::const_numtraits::ConstMidpoint;
19use crate::machineword::ConstMachineWord;
20use crate::personality::Personality;
21
22c0nst::c0nst! {
23    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstMidpoint for FixedUInt<T, N, P> {
24        fn midpoint(self, rhs: Self) -> Self {
25            // (a & b) + ((a ^ b) >> 1) avoids overflow
26            (self & rhs) + ((self ^ rhs) >> 1usize)
27        }
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn test_midpoint() {
37        type U16 = FixedUInt<u8, 2>;
38
39        // Simple midpoint
40        assert_eq!(
41            ConstMidpoint::midpoint(U16::from(0u8), U16::from(10u8)),
42            U16::from(5u8)
43        );
44
45        // Order doesn't matter
46        assert_eq!(
47            ConstMidpoint::midpoint(U16::from(10u8), U16::from(0u8)),
48            U16::from(5u8)
49        );
50
51        // Midpoint rounds down
52        assert_eq!(
53            ConstMidpoint::midpoint(U16::from(0u8), U16::from(9u8)),
54            U16::from(4u8)
55        );
56
57        // Same values
58        assert_eq!(
59            ConstMidpoint::midpoint(U16::from(42u8), U16::from(42u8)),
60            U16::from(42u8)
61        );
62
63        // Max values (no overflow)
64        let max = U16::from(0xFFFFu16);
65        assert_eq!(ConstMidpoint::midpoint(max, max), max);
66
67        // 0 and max
68        assert_eq!(
69            ConstMidpoint::midpoint(U16::from(0u8), max),
70            U16::from(0x7FFFu16)
71        );
72    }
73
74    c0nst::c0nst! {
75        pub c0nst fn const_midpoint<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
76            a: FixedUInt<T, N, P>,
77            b: FixedUInt<T, N, P>,
78        ) -> FixedUInt<T, N, P> {
79            ConstMidpoint::midpoint(a, b)
80        }
81    }
82
83    #[test]
84    fn test_const_midpoint() {
85        type U16 = FixedUInt<u8, 2>;
86
87        assert_eq!(
88            const_midpoint(U16::from(0u8), U16::from(10u8)),
89            U16::from(5u8)
90        );
91
92        #[cfg(feature = "nightly")]
93        {
94            const A: U16 = FixedUInt::from_array([0, 0]);
95            const B: U16 = FixedUInt::from_array([10, 0]);
96            const MID: U16 = const_midpoint(A, B);
97            assert_eq!(MID, FixedUInt::from_array([5, 0]));
98
99            // Test with max values
100            const MAX: U16 = FixedUInt::from_array([0xFF, 0xFF]);
101            const MID_MAX: U16 = const_midpoint(MAX, MAX);
102            assert_eq!(MID_MAX, MAX);
103        }
104    }
105
106    /// Polymorphic test: verify midpoint produces identical results across
107    /// different word layouts for the same values.
108    #[test]
109    fn test_midpoint_polymorphic() {
110        fn test_mid<T>(a: T, b: T, expected: T)
111        where
112            T: ConstMidpoint + Eq + core::fmt::Debug + Copy,
113        {
114            assert_eq!(ConstMidpoint::midpoint(a, b), expected);
115            assert_eq!(ConstMidpoint::midpoint(b, a), expected); // order doesn't matter
116        }
117
118        // Test with different layouts
119        type U8x2 = FixedUInt<u8, 2>;
120        type U8x4 = FixedUInt<u8, 4>;
121        type U16x2 = FixedUInt<u16, 2>;
122
123        // 0 and 100
124        test_mid(U8x2::from(0u8), U8x2::from(100u8), U8x2::from(50u8));
125        test_mid(U8x4::from(0u8), U8x4::from(100u8), U8x4::from(50u8));
126        test_mid(U16x2::from(0u8), U16x2::from(100u8), U16x2::from(50u8));
127
128        // Same with primitives
129        test_mid(0u8, 100u8, 50u8);
130        test_mid(0u16, 100u16, 50u16);
131        test_mid(0u32, 100u32, 50u32);
132
133        // Rounding down: (0 + 99) / 2 = 49.5 -> 49
134        test_mid(U8x2::from(0u8), U8x2::from(99u8), U8x2::from(49u8));
135        test_mid(0u8, 99u8, 49u8);
136
137        // Large values that would overflow with naive (a+b)/2
138        let max_u16 = U8x2::from(0xFFFFu16);
139        test_mid(max_u16, max_u16, max_u16);
140        test_mid(u16::MAX, u16::MAX, u16::MAX);
141    }
142}