diff options
| author | Vadzim Dambrouski <pftbest@gmail.com> | 2017-03-26 01:01:54 +0300 |
|---|---|---|
| committer | Vadzim Dambrouski <pftbest@gmail.com> | 2017-03-26 20:37:04 +0300 |
| commit | fda8e1571f7a0c4da77c57bc7a7728c4ed1e6aea (patch) | |
| tree | 5aab7b160b4bc0391b7cd44a138c32f05a441ba7 | |
| parent | 7846dbe0c8de17f59cdfc3d2b914d58faad7eade (diff) | |
| download | rust-fda8e1571f7a0c4da77c57bc7a7728c4ed1e6aea.tar.gz rust-fda8e1571f7a0c4da77c57bc7a7728c4ed1e6aea.zip | |
libcore: sort_unstable: improve randomization in break_patterns.
Select 3 random points instead of just 1. Also the code now compiles on 16bit architectures.
| -rw-r--r-- | src/libcore/slice/sort.rs | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 307e4974d97..3612ee65bca 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -498,32 +498,40 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize #[cold] fn break_patterns<T>(v: &mut [T]) { let len = v.len(); - if len >= 8 { - // A random number will be taken modulo this one. The modulus is a power of two so that we - // can simply take bitwise "and", thus avoiding costly CPU operations. - let modulus = (len / 4).next_power_of_two(); - debug_assert!(modulus >= 1 && modulus <= len / 2); - - // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia. - let mut random = len; - random ^= random << 13; - random ^= random >> 17; - random ^= random << 5; - random &= modulus - 1; - debug_assert!(random < len / 2); - - // The first index. - let a = len / 4 * 2; - debug_assert!(a >= 1 && a < len - 2); - - // The second index. - let b = len / 4 + random; - debug_assert!(b >= 1 && b < len - 2); - - // Swap neighbourhoods of `a` and `b`. + // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. + let mut random = len as u32; + let mut gen_u32 = || { + random ^= random << 13; + random ^= random >> 17; + random ^= random << 5; + random + }; + let mut gen_usize = || { + if mem::size_of::<usize>() <= 4 { + gen_u32() as usize + } else { + (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize + } + }; + + // Take random numbers modulo this number. + // The number fits into `usize` because `len` is not greater than `isize::MAX`. + let modulus = len.next_power_of_two(); + + // Some pivot candidates will be in the nearby of this index. Let's randomize them. + let pos = len / 4 * 2; + for i in 0..3 { - v.swap(a - 1 + i, b - 1 + i); + // Generate a random number modulo `len`. However, in order to avoid costly operations + // we first take it modulo a power of two, and then decrease by `len` until it fits + // into the range `[0, len - 1]`. + let mut other = gen_usize() & (modulus - 1); + while other >= len { + other -= len; + } + + v.swap(pos - 1 + i, other); } } } |
