Skip to main content

malachite_base/num/arithmetic/
average.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{Average, AverageAssign, AverageRound, AverageRoundAssign};
10use crate::num::basic::floats::PrimitiveFloat;
11use crate::num::basic::integers::PrimitiveInt;
12use crate::rounding_modes::RoundingMode::{self, *};
13use core::cmp::Ordering::{self, *};
14
15// Since x + y == 2(x & y) + (x ^ y), the floor of the average is (x & y) + ((x ^ y) >> 1), with an
16// arithmetic shift for signed types, and neither the shift nor the addition can overflow. The
17// average is either exact or a half more than the floor, so the ceiling, when it differs from the
18// floor, is one more and cannot overflow either.
19fn average_round_primitive<T: PrimitiveInt>(x: T, y: T, rm: RoundingMode) -> (T, Ordering) {
20    let floor = (x & y) + ((x ^ y) >> 1);
21    if (x ^ y).even() {
22        return (floor, Equal);
23    }
24    match rm {
25        Floor => (floor, Less),
26        Ceiling => (floor + T::ONE, Greater),
27        Down => {
28            if floor < T::ZERO {
29                (floor + T::ONE, Greater)
30            } else {
31                (floor, Less)
32            }
33        }
34        Up => {
35            if floor < T::ZERO {
36                (floor, Less)
37            } else {
38                (floor + T::ONE, Greater)
39            }
40        }
41        Nearest => {
42            if floor.even() {
43                (floor, Less)
44            } else {
45                (floor + T::ONE, Greater)
46            }
47        }
48        Exact => {
49            panic!("Average is not exact: ({x} + {y}) / 2");
50        }
51    }
52}
53
54macro_rules! impl_average {
55    ($t:ident) => {
56        impl AverageRound<$t> for $t {
57            type Output = $t;
58
59            /// Computes the average (arithmetic mean) of two numbers and rounds according to a
60            /// specified rounding mode. An [`Ordering`] is also returned, indicating whether the
61            /// returned value is less than, equal to, or greater than the exact value.
62            ///
63            /// The average is computed without overflow; the result always fits in the same type as
64            /// the inputs.
65            ///
66            /// Let $a = \frac{x + y}{2}$, and let $g$ be the function that just returns the first
67            /// element of the pair, without the [`Ordering`]. Since $a$ is either an integer or a
68            /// half more than an integer,
69            ///
70            /// $$
71            /// g(x, y, \mathrm{Floor}) = \lfloor a \rfloor,
72            /// $$
73            ///
74            /// $$
75            /// g(x, y, \mathrm{Ceiling}) = \lceil a \rceil,
76            /// $$
77            ///
78            /// $$
79            /// g(x, y, \mathrm{Down}) = \operatorname{sgn}(a) \lfloor |a| \rfloor,
80            /// $$
81            ///
82            /// $$
83            /// g(x, y, \mathrm{Up}) = \operatorname{sgn}(a) \lceil |a| \rceil,
84            /// $$
85            ///
86            /// $$
87            /// g(x, y, \mathrm{Nearest}) = \begin{cases}
88            ///     a & \text{if} \\quad a \in \Z, \\\\
89            ///     \lfloor a \rfloor & \text{if} \\quad a \notin \Z
90            ///     \\ \text{and} \\ \lfloor a \rfloor \\ \text{is even}, \\\\
91            ///     \lceil a \rceil & \text{if} \\quad a \notin \Z
92            ///     \\ \text{and} \\ \lfloor a \rfloor \\ \text{is odd,}
93            /// \end{cases}
94            /// $$
95            ///
96            /// and $g(x, y, \mathrm{Exact}) = a$, but panics if $a \notin \Z$.
97            ///
98            /// Then
99            ///
100            /// $f(x, y, r) = (g(x, y, r), \operatorname{cmp}(g(x, y, r), a))$.
101            ///
102            /// # Worst-case complexity
103            /// Constant time and additional memory.
104            ///
105            /// # Panics
106            /// Panics if `rm` is `Exact` but the average of `self` and `other` is not an integer.
107            ///
108            /// # Examples
109            /// See [here](super::average#average_round).
110            #[inline]
111            fn average_round(self, other: $t, rm: RoundingMode) -> ($t, Ordering) {
112                average_round_primitive(self, other, rm)
113            }
114        }
115
116        impl AverageRoundAssign<$t> for $t {
117            /// Computes the average (arithmetic mean) of two numbers, rounding according to a
118            /// specified rounding mode and replacing the first number with it. An [`Ordering`] is
119            /// returned, indicating whether the assigned value is less than, equal to, or greater
120            /// than the exact value.
121            ///
122            /// The average is computed without overflow; the result always fits in the same type as
123            /// the inputs.
124            ///
125            /// See the [`AverageRound`](super::traits::AverageRound) documentation for details.
126            ///
127            /// # Worst-case complexity
128            /// Constant time and additional memory.
129            ///
130            /// # Panics
131            /// Panics if `rm` is `Exact` but the average of `self` and `other` is not an integer.
132            ///
133            /// # Examples
134            /// See [here](super::average#average_round_assign).
135            #[inline]
136            fn average_round_assign(&mut self, other: $t, rm: RoundingMode) -> Ordering {
137                let o;
138                (*self, o) = average_round_primitive(*self, other, rm);
139                o
140            }
141        }
142
143        impl Average<$t> for $t {
144            type Output = $t;
145
146            /// Computes the average (arithmetic mean) of two numbers, rounding to the nearest
147            /// integer. Two-way ties are broken by rounding to the even integer.
148            ///
149            /// The average is computed without overflow; the result always fits in the same type as
150            /// the inputs. This is equivalent to
151            /// [`average_round`](super::traits::AverageRound::average_round) with
152            /// [`Nearest`](crate::rounding_modes::RoundingMode::Nearest).
153            ///
154            /// $$
155            /// f(x, y) = \begin{cases}
156            ///     a & \text{if} \\quad a \in \Z, \\\\
157            ///     \lfloor a \rfloor & \text{if} \\quad a \notin \Z
158            ///     \\ \text{and} \\ \lfloor a \rfloor \\ \text{is even}, \\\\
159            ///     \lceil a \rceil & \text{if} \\quad a \notin \Z
160            ///     \\ \text{and} \\ \lfloor a \rfloor \\ \text{is odd,}
161            /// \end{cases}
162            /// $$
163            ///
164            /// where $a = \frac{x + y}{2}$.
165            ///
166            /// # Worst-case complexity
167            /// Constant time and additional memory.
168            ///
169            /// # Examples
170            /// See [here](super::average#average).
171            #[inline]
172            fn average(self, other: $t) -> $t {
173                average_round_primitive(self, other, Nearest).0
174            }
175        }
176
177        impl AverageAssign<$t> for $t {
178            /// Computes the average (arithmetic mean) of two numbers, rounding to the nearest
179            /// integer and replacing the first number with it. Two-way ties are broken by rounding
180            /// to the even integer.
181            ///
182            /// The average is computed without overflow; the result always fits in the same type as
183            /// the inputs.
184            ///
185            /// See the [`Average`](super::traits::Average) documentation for details.
186            ///
187            /// # Worst-case complexity
188            /// Constant time and additional memory.
189            ///
190            /// # Examples
191            /// See [here](super::average#average_assign).
192            #[inline]
193            fn average_assign(&mut self, other: $t) {
194                *self = average_round_primitive(*self, other, Nearest).0;
195            }
196        }
197    };
198}
199apply_to_primitive_ints!(impl_average);
200
201// The three-case midpoint algorithm used by C++'s `std::midpoint`. When both inputs are at most
202// half the maximum, the sum cannot overflow, and (x + y) / 2 is correctly rounded: an addition
203// whose result lands in the subnormal range is exact, so the sum and the halving never both round.
204// Otherwise at least one input is huge. An input too small to halve exactly is added whole; its
205// halving error is far below the rounding quantum of the huge input's half, so the result is
206// unaffected. Everything else is halved exactly first.
207fn average_primitive_float<T: PrimitiveFloat>(x: T, y: T) -> T {
208    if !x.is_finite() || !y.is_finite() {
209        // for infinities and NaNs, behave exactly like the naive expression
210        return (x + y) / T::TWO;
211    }
212    let half_max = T::MAX_FINITE / T::TWO;
213    let double_min = T::MIN_POSITIVE_NORMAL * T::TWO;
214    let abs_x = x.abs();
215    let abs_y = y.abs();
216    if abs_x <= half_max && abs_y <= half_max {
217        (x + y) / T::TWO
218    } else if abs_x < double_min {
219        x + y / T::TWO
220    } else if abs_y < double_min {
221        x / T::TWO + y
222    } else {
223        x / T::TWO + y / T::TWO
224    }
225}
226
227macro_rules! impl_average_primitive_float {
228    ($t:ident) => {
229        impl Average<$t> for $t {
230            type Output = $t;
231
232            /// Computes the average (arithmetic mean) of two floating-point numbers.
233            ///
234            /// For finite values the result is the correctly rounded average: the nearest
235            /// representable value, with ties going to the value with the even mantissa. The
236            /// computation avoids intermediate overflow and underflow, so extreme values average
237            /// correctly. If either value is infinite or `NaN`, the result is whatever `(x + y) /
238            /// 2.0` produces.
239            ///
240            /// # Worst-case complexity
241            /// Constant time and additional memory.
242            ///
243            /// # Examples
244            /// See [here](super::average#average).
245            #[inline]
246            fn average(self, other: $t) -> $t {
247                average_primitive_float(self, other)
248            }
249        }
250
251        impl AverageAssign<$t> for $t {
252            /// Computes the average (arithmetic mean) of two floating-point numbers, replacing the
253            /// first number with it.
254            ///
255            /// For finite values the result is the correctly rounded average: the nearest
256            /// representable value, with ties going to the value with the even mantissa. The
257            /// computation avoids intermediate overflow and underflow, so extreme values average
258            /// correctly. If either value is infinite or `NaN`, the result is whatever `(x + y) /
259            /// 2.0` produces.
260            ///
261            /// # Worst-case complexity
262            /// Constant time and additional memory.
263            ///
264            /// # Examples
265            /// See [here](super::average#average_assign).
266            #[inline]
267            fn average_assign(&mut self, other: $t) {
268                *self = average_primitive_float(*self, other);
269            }
270        }
271    };
272}
273apply_to_primitive_floats!(impl_average_primitive_float);