replace midpoint with mean

midpoint makes more sense for integers, where it would be used for
example to find the midpoint in a binary search. With floating-point
and fixed-point numbers, it makes more sense to talk about mean.
This commit is contained in:
Trevor Spiteri 2021-03-21 19:23:31 +01:00
parent 94f5042bf1
commit 05c5f398cf
6 changed files with 27 additions and 48 deletions

View File

@ -94,7 +94,7 @@ The conversions supported cover the following cases.
* [`to_be`][f-tb-1-7], [`to_le`][f-tl-1-7]
* [`swap_bytes`][f-sb-1-7]
* [`reverse_bits`][f-rb-1-7]
* [`midpoint`][f-m-1-7]
* [`mean`][f-m-1-7]
* The following methods were added to the [`Wrapping`][w-1-7] and
[`Unwrapped`][u-1-7] wrappers:
* [`from_be_bytes`][f-fbb-1-7], [`from_le_bytes`][f-flb-1-7],
@ -153,7 +153,7 @@ The conversions supported cover the following cases.
[f-fnb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.from_ne_bytes
[f-ho-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedU32.html#method.highest_one
[f-is-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#associatedconstant.IS_SIGNED
[f-m-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.midpoint
[f-m-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.mean
[f-npot-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedU32.html#method.next_power_of_two
[f-rb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.reverse_bits
[f-sb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.swap_bytes

View File

@ -21,7 +21,7 @@ Version 1.7.0 (unreleased)
* [`to_be`][f-tb-1-7], [`to_le`][f-tl-1-7]
* [`swap_bytes`][f-sb-1-7]
* [`reverse_bits`][f-rb-1-7]
* [`midpoint`][f-m-1-7]
* [`mean`][f-m-1-7]
* The following methods were added to the [`Wrapping`][w-1-7] and
[`Unwrapped`][u-1-7] wrappers:
* [`from_be_bytes`][f-fbb-1-7], [`from_le_bytes`][f-flb-1-7],
@ -78,7 +78,7 @@ Version 1.7.0 (unreleased)
[f-fnb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.from_ne_bytes
[f-ho-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedU32.html#method.highest_one
[f-is-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#associatedconstant.IS_SIGNED
[f-m-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.midpoint
[f-m-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.mean
[f-npot-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedU32.html#method.next_power_of_two
[f-rb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.reverse_bits
[f-sb-1-7]: https://tspiteri.gitlab.io/fixed/dev/fixed/struct.FixedI32.html#method.swap_bytes

View File

@ -899,51 +899,30 @@ assert_eq!(Fix::from_num(6.5).next_power_of_two(), Fix::from_num(8));
}
comment! {
"Returns the midpoint of `self` and `other`, rounding towards `self`.
"Returns the mean of `self` and `other`.
# Examples
```rust
use fixed::{types::extra::U4, ", $s_fixed, "};
type Fix = ", $s_fixed, "<U4>;
assert_eq!(Fix::from_num(3).midpoint(Fix::from_num(4)), Fix::from_num(3.5));
assert_eq!(Fix::from_num(3).mean(Fix::from_num(4)), Fix::from_num(3.5));
",
if_signed_else_empty_str! {
$Signedness,
"assert_eq!(Fix::from_num(-3).midpoint(Fix::from_num(4)), Fix::from_num(0.5));
"assert_eq!(Fix::from_num(-3).mean(Fix::from_num(4)), Fix::from_num(0.5));
",
},
"
// Midpoint of 0b0.0011 and 0b0.00100 is 0b0.0011_1, which has to be rounded.
assert_eq!(Fix::from_bits(3).midpoint(Fix::from_bits(4)), Fix::from_bits(3));
assert_eq!(Fix::from_bits(4).midpoint(Fix::from_bits(3)), Fix::from_bits(4));
```
"```
";
#[inline]
pub const fn midpoint(self, other: $Fixed<Frac>) -> $Fixed<Frac> {
// This shoud return a + (b - a) / 2, where / 2 rounds
// towards zero so that the midpoint rounds towards a.
//
// The first step replaces division with rounding to 0, / 2,
// with flooring division, >> 1.
// This is necessary because (2 * x + y) / 2 is not always = x + y / 2,
// because the signum of the dividend affects the rounding direction,
// but (2 * x + y) >> 1 is always = x + (y >> 1).
//
// a + (b - a) / 2
// = a + ((b - a + b<a) >> 1)
// = 2 * (a>>1) + (a&1) + ((2 * (b>>1) + (b&1) - 2 * (a>>1) - (a&1) + b<a) >> 1)
// = 2 * (a>>1) + (a&1) + (b>>1) - (a>>1) + (((b&1) - (a&1) + b<a) >> 1)
// = (a>>1) + (b>>1) + (a&1) + (((b&1) - (a&1) + b<a) >> 1)
// = (a>>1) + (b>>1) + ((2 * (a&1) + (b&1) - (a&1) + b<a) >> 1)
// = (a>>1) + (b>>1) + (((a&1) + (b&1) + b<a) >> 1)
// Let inc = (((a&1) + (b&1) + b<a) >> 1).
// Then inc is 1 if two or three of (a&1), (b&1), (b<a) are 1, and 0 otherwise.
// That is, if b < a then inc is (a&1) | (b&1), else inc is (a&1) & (b&1).
// That is, if b < a then inc is 1 & (a|b), else inc is 1 & (a&b).
pub const fn mean(self, other: $Fixed<Frac>) -> $Fixed<Frac> {
// a & b == common bits
// a ^ b == different bits
// a + b == 2 * (a & b) + (a ^ b)
// (a + b) / 2 = (a & b) + (a ^ b) / 2
let (a, b) = (self.to_bits(), other.to_bits());
let inc = 1 & if b < a { a | b } else { a & b };
$Fixed::from_bits((a >> 1) + (b >> 1) + inc)
$Fixed::from_bits((a & b) + ((a ^ b) >> 1))
}
}

View File

@ -827,8 +827,8 @@ where
/// Shifts to the right by `n` bits, wrapping the truncated bits to the left end.
fn rotate_right(self, n: u32) -> Self;
/// Returns the midpoint of `self` and `other`, rounding towards `self`.
fn midpoint(self, other: Self) -> Self;
/// Returns the mean of `self` and `other`.
fn mean(self, other: Self) -> Self;
/// Returns the reciprocal.
///
@ -2498,7 +2498,7 @@ macro_rules! impl_fixed {
trait_delegate! { fn reverse_bits(self) -> Self }
trait_delegate! { fn rotate_left(self, n: u32) -> Self }
trait_delegate! { fn rotate_right(self, n: u32) -> Self }
trait_delegate! { fn midpoint(self, other: Self) -> Self }
trait_delegate! { fn mean(self, other: Self) -> Self }
trait_delegate! { fn recip(self) -> Self }
trait_delegate! { fn mul_add(self, mul: Self, add: Self) -> Self }
trait_delegate! { fn div_euclid(self, rhs: Self) -> Self }

View File

@ -845,7 +845,7 @@ impl<F: Fixed> Unwrapped<F> {
Unwrapped(self.0.rotate_right(n))
}
/// Returns the midpoint of `self` and `other`, rounding towards `self`.
/// Returns the mean of `self` and `other`.
///
/// # Examples
///
@ -853,12 +853,12 @@ impl<F: Fixed> Unwrapped<F> {
/// use fixed::{types::I16F16, Unwrapped};
/// let three = Unwrapped(I16F16::from_num(3));
/// let four = Unwrapped(I16F16::from_num(4));
/// assert_eq!(three.midpoint(four), Unwrapped(I16F16::from_num(3.5)));
/// assert_eq!(three.midpoint(-four), Unwrapped(I16F16::from_num(-0.5)));
/// assert_eq!(three.mean(four), Unwrapped(I16F16::from_num(3.5)));
/// assert_eq!(three.mean(-four), Unwrapped(I16F16::from_num(-0.5)));
/// ```
#[inline]
pub fn midpoint(self, other: Unwrapped<F>) -> Unwrapped<F> {
Unwrapped(self.0.midpoint(other.0))
pub fn mean(self, other: Unwrapped<F>) -> Unwrapped<F> {
Unwrapped(self.0.mean(other.0))
}
/// Returns the reciprocal (inverse), 1/`self`.

View File

@ -801,7 +801,7 @@ impl<F: Fixed> Wrapping<F> {
Wrapping(self.0.rotate_right(n))
}
/// Returns the midpoint of `self` and `other`, rounding towards `self`.
/// Returns the mean of `self` and `other`.
///
/// # Examples
///
@ -809,12 +809,12 @@ impl<F: Fixed> Wrapping<F> {
/// use fixed::{types::I16F16, Wrapping};
/// let three = Wrapping(I16F16::from_num(3));
/// let four = Wrapping(I16F16::from_num(4));
/// assert_eq!(three.midpoint(four), Wrapping(I16F16::from_num(3.5)));
/// assert_eq!(three.midpoint(-four), Wrapping(I16F16::from_num(-0.5)));
/// assert_eq!(three.mean(four), Wrapping(I16F16::from_num(3.5)));
/// assert_eq!(three.mean(-four), Wrapping(I16F16::from_num(-0.5)));
/// ```
#[inline]
pub fn midpoint(self, other: Wrapping<F>) -> Wrapping<F> {
Wrapping(self.0.midpoint(other.0))
pub fn mean(self, other: Wrapping<F>) -> Wrapping<F> {
Wrapping(self.0.mean(other.0))
}
/// Returns the reciprocal (inverse), 1/`self`.