Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
406852a
Resolve overflow behavior for RangeFrom
CAD97 May 20, 2020
a8ed9aa
impl From<[T; N]> for Box<[T]>
pickfire Apr 13, 2020
96f3879
impl Step for char
CAD97 May 21, 2020
c25b82f
Use Step::forward_unchecked in RangeInclusive::next
CAD97 May 21, 2020
34b5118
Suggest using std::mem::drop function instead of explicit destructor …
stanislav-tkach May 20, 2020
27d1cd8
Add safety annotations in iter::range
CAD97 May 21, 2020
b1d1f25
Add a test for char ranges
CAD97 May 21, 2020
a9199de
Merge spans for the suggestion
stanislav-tkach May 22, 2020
68bab3e
Add total_cmp to f32 and f64, plus tests
golddranks May 22, 2020
b6eec22
Fix typo in src/libcore/num/f32.rs
golddranks May 25, 2020
d6650e0
Fix typo in src/libcore/num/f32.rs
golddranks May 25, 2020
bd68de8
remove unneeded and unidiomatic must_use
golddranks May 25, 2020
6973fd7
Add bit twiddling
golddranks May 25, 2020
8bc31ff
Fix the same typos again orz
golddranks May 25, 2020
c3dc8c4
Rename upvar_list to closure_captures
May 25, 2020
66da735
Add tracing issue for total_cmp
golddranks May 26, 2020
ca722b9
Add test for #56445
JohnTitor May 25, 2020
125f0ab
Add test for #68532
JohnTitor May 25, 2020
4b87f97
Add test for #70121
JohnTitor May 25, 2020
6315d0c
Add test for #71042
JohnTitor May 26, 2020
6ddbef1
Simplify suggestion
stanislav-tkach May 26, 2020
822ad87
Add Peekable::next_if
jyn514 May 18, 2020
709ddba
Allow types (with lifetimes/generics) in impl_lint_pass
flip1995 May 27, 2020
b124892
Add test for {impl,declare}_lint_pass macros
flip1995 May 27, 2020
cd6a8ca
FIx off-by-one in char::steps_between
CAD97 May 28, 2020
52ed89a
from_u32_unchecked: check validity when debug assertions are enabled
RalfJung May 28, 2020
ce81d15
Add test to make sure -Wunused-crate-dependencies works with tests
jsgf May 28, 2020
d5e6bda
Make remote-test-client and remote-test-server compatible with windows
seritools May 27, 2020
2adbfa9
Unify temp path generation for non-android
seritools May 28, 2020
36d6791
Fix `set_permissions` call for non-windows
seritools May 29, 2020
03fe603
Rollup merge of #71095 - pickfire:box-from-array, r=dtolnay
Dylan-DPC May 29, 2020
ee1a4bc
Rollup merge of #72310 - jyn514:peekable-next-if, r=dtolnay
Dylan-DPC May 29, 2020
077383d
Rollup merge of #72368 - CAD97:rangeto, r=dtolnay
Dylan-DPC May 29, 2020
b08978e
Rollup merge of #72383 - DarkEld3r:issue-72322, r=matthewjasper
Dylan-DPC May 29, 2020
b88dc2e
Rollup merge of #72413 - CAD97:char-range, r=dtolnay
Dylan-DPC May 29, 2020
bc61a5f
Rollup merge of #72568 - golddranks:add_total_cmp_to_floats, r=sfackler
Dylan-DPC May 29, 2020
5109c96
Rollup merge of #72572 - JohnTitor:add-tests, r=matthewjasper
Dylan-DPC May 29, 2020
343ea07
Rollup merge of #72591 - sexxi-goose:rename_upvar_list-to-closure_cap…
Dylan-DPC May 29, 2020
a3d1c79
Rollup merge of #72657 - flip1995:impl_lint_pass-ty, r=matthewjasper
Dylan-DPC May 29, 2020
9279a6a
Rollup merge of #72672 - seritools:remote-test-windows, r=Mark-Simula…
Dylan-DPC May 29, 2020
793967b
Rollup merge of #72683 - RalfJung:char-debug-check, r=Mark-Simulacrum
Dylan-DPC May 29, 2020
ebac81e
Rollup merge of #72710 - jsgf:unused-deps-test, r=jsgf
Dylan-DPC May 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add total_cmp to f32 and f64, plus tests
  • Loading branch information
golddranks committed May 25, 2020
commit 68bab3e56e7df618c093f5b93901f5319ef65997
73 changes: 73 additions & 0 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,4 +810,77 @@ impl f32 {
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
Self::from_bits(u32::from_ne_bytes(bytes))
}

/// Returns an ordering between self and other values.
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
/// floating point standard. The values are ordered in following order:
/// - Negative quiet NaN
/// - Negative signaling NaN
/// - Negative infinity
/// - Negative numbers
/// - Negative subnormal numbers
/// - Negative zero
/// - Positive zero
/// - Positive subnormal numbers
/// - Positive numbers
/// - Positive infinity
/// - Positive signaling NaN
/// - Positive quiet NaN
///
/// # Example
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
/// name: String,
/// weight: f32,
/// }
///
/// let mut bois = vec![
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
/// GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY },
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
/// ];
///
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
/// # assert!(bois.into_iter().map(|b| b.weight)
/// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "total_cmp", issue = "none")]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i32;
let mut right = other.to_bits() as i32;

// In case of negatives, flip all the bits expect the sign
// to achieve a similar layout as two's complement integers
//
// Why does this work? IEEE 754 floats consist of three fields:
// Sign bit, exponent and mantissa. The set of exponent and mantissa
// fields as a whole have the property that their bitwise order is
// equal to the numeric magnitude where the magnitude is defined.
// The magnitude is not normally defined on NaN values, but
// IEEE 754 totalOrder defines the NaN values also to follow the
// bitwise order. This leads to order explained in the doc comment.
// However, the representation of magnitude is the same for negative
// and positive numbers – only the sign bit is different.
// To easily compare the floats as signed integers, we need to
// flip the exponent and mantissa bits in case of negative numbers.
// We effectively convert the numbers to "two's complement" form.
if left < 0 {
// i32::MAX corresponds the bit pattern of "all ones expect for the sign bit"
left ^= i32::MAX
};
if right < 0 {
right ^= i32::MAX
};

left.cmp(&right)
}
}
73 changes: 73 additions & 0 deletions src/libcore/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,4 +824,77 @@ impl f64 {
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
Self::from_bits(u64::from_ne_bytes(bytes))
}

/// Returns an ordering between self and other values.
/// Unlike the standard partial comparison between floating point numbers,
/// this comparison always produces an ordering in accordance to
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
/// floating point standard. The values are ordered in following order:
/// - Negative quiet NaN
/// - Negative signaling NaN
/// - Negative infinity
/// - Negative numbers
/// - Negative subnormal numbers
/// - Negative zero
/// - Positive zero
/// - Positive subnormal numbers
/// - Positive numbers
/// - Positive infinity
/// - Positive signaling NaN
/// - Positive quiet NaN
///
/// # Example
/// ```
/// #![feature(total_cmp)]
/// struct GoodBoy {
/// name: String,
/// weight: f64,
/// }
///
/// let mut bois = vec![
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
/// GoodBoy { name: "Chonk".to_owned(), weight: f64::INFINITY },
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN },
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
/// ];
///
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
/// # assert!(bois.into_iter().map(|b| b.weight)
/// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter())
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[must_use = "method returns a new number and does not mutate the original value"]
#[unstable(feature = "total_cmp", issue = "none")]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i64;
let mut right = other.to_bits() as i64;

// In case of negatives, flip all the bits expect the sign
// to achieve a similar layout as two's complement integers
//
// Why does this work? IEEE 754 floats consist of three fields:
// Sign bit, exponent and mantissa. The set of exponent and mantissa
// fields as a whole have the property that their bitwise order is
// equal to the numeric magnitude where the magnitude is defined.
// The magnitude is not normally defined on NaN values, but
// IEEE 754 totalOrder defines the NaN values also to follow the
// bitwise order. This leads to order explained in the doc comment.
// However, the representation of magnitude is the same for negative
// and positive numbers – only the sign bit is different.
// To easily compare the floats as signed integers, we need to
// flip the exponent and mantissa bits in case of negative numbers.
// We effectively convert the numbers to "two's complement" form.
if left < 0 {
// i64::MAX corresponds the bit pattern of "all ones expect for the sign bit"
left ^= i64::MAX
};
if right < 0 {
right ^= i64::MAX
};

left.cmp(&right)
}
}
143 changes: 143 additions & 0 deletions src/libstd/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1531,4 +1531,147 @@ mod tests {
fn test_clamp_max_is_nan() {
let _ = 1.0f32.clamp(3.0, NAN);
}

#[test]
fn test_total_cmp() {
use core::cmp::Ordering;

fn quiet_bit_mask() -> u32 {
1 << (f32::MANTISSA_DIGITS - 2)
}

fn min_subnorm() -> f32 {
f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0)
}

fn max_subnorm() -> f32 {
f32::MIN_POSITIVE - min_subnorm()
}

fn q_nan() -> f32 {
f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask())
}

fn s_nan() -> f32 {
f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42)
}

assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0));
assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0));
assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5));
assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0));
assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX));
assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan()));
assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan()));

assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0));
assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5));
assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5));
assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5));
assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan()));
assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan()));

assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan()));
assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan()));
assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5));
assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5));
assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0));
assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5));
assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0));
assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0));
assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm()));
assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm()));
assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5));
assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0));
assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5));
assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5));
assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX));
assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan()));

assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan()));

assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm()));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
}
Loading