Coverage Report

Created: 2026-08-14 08:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rand-0.8.6/src/distributions/utils.rs
Line
Count
Source
1
// Copyright 2018 Developers of the Rand project.
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8
9
//! Math helper functions
10
11
12
pub(crate) trait WideningMultiply<RHS = Self> {
13
    type Output;
14
15
    fn wmul(self, x: RHS) -> Self::Output;
16
}
17
18
macro_rules! wmul_impl {
19
    ($ty:ty, $wide:ty, $shift:expr) => {
20
        impl WideningMultiply for $ty {
21
            type Output = ($ty, $ty);
22
23
            #[inline(always)]
24
0
            fn wmul(self, x: $ty) -> Self::Output {
25
0
                let tmp = (self as $wide) * (x as $wide);
26
0
                ((tmp >> $shift) as $ty, tmp as $ty)
27
0
            }
Unexecuted instantiation: <u16 as rand::distributions::utils::WideningMultiply>::wmul
Unexecuted instantiation: <u32 as rand::distributions::utils::WideningMultiply>::wmul
Unexecuted instantiation: <u64 as rand::distributions::utils::WideningMultiply>::wmul
Unexecuted instantiation: <u8 as rand::distributions::utils::WideningMultiply>::wmul
28
        }
29
    };
30
31
    // simd bulk implementation
32
    ($(($ty:ident, $wide:ident),)+, $shift:expr) => {
33
        $(
34
            impl WideningMultiply for $ty {
35
                type Output = ($ty, $ty);
36
37
                #[inline(always)]
38
                fn wmul(self, x: $ty) -> Self::Output {
39
                    // For supported vectors, this should compile to a couple
40
                    // supported multiply & swizzle instructions (no actual
41
                    // casting).
42
                    // TODO: optimize
43
                    let y: $wide = self.cast();
44
                    let x: $wide = x.cast();
45
                    let tmp = y * x;
46
                    let hi: $ty = (tmp >> $shift).cast();
47
                    let lo: $ty = tmp.cast();
48
                    (hi, lo)
49
                }
50
            }
51
        )+
52
    };
53
}
54
wmul_impl! { u8, u16, 8 }
55
wmul_impl! { u16, u32, 16 }
56
wmul_impl! { u32, u64, 32 }
57
wmul_impl! { u64, u128, 64 }
58
59
// This code is a translation of the __mulddi3 function in LLVM's
60
// compiler-rt. It is an optimised variant of the common method
61
// `(a + b) * (c + d) = ac + ad + bc + bd`.
62
//
63
// For some reason LLVM can optimise the C version very well, but
64
// keeps shuffling registers in this Rust translation.
65
macro_rules! wmul_impl_large {
66
    ($ty:ty, $half:expr) => {
67
        impl WideningMultiply for $ty {
68
            type Output = ($ty, $ty);
69
70
            #[inline(always)]
71
0
            fn wmul(self, b: $ty) -> Self::Output {
72
                const LOWER_MASK: $ty = !0 >> $half;
73
0
                let mut low = (self & LOWER_MASK).wrapping_mul(b & LOWER_MASK);
74
0
                let mut t = low >> $half;
75
0
                low &= LOWER_MASK;
76
0
                t += (self >> $half).wrapping_mul(b & LOWER_MASK);
77
0
                low += (t & LOWER_MASK) << $half;
78
0
                let mut high = t >> $half;
79
0
                t = low >> $half;
80
0
                low &= LOWER_MASK;
81
0
                t += (b >> $half).wrapping_mul(self & LOWER_MASK);
82
0
                low += (t & LOWER_MASK) << $half;
83
0
                high += t >> $half;
84
0
                high += (self >> $half).wrapping_mul(b >> $half);
85
86
0
                (high, low)
87
0
            }
88
        }
89
    };
90
91
    // simd bulk implementation
92
    (($($ty:ty,)+) $scalar:ty, $half:expr) => {
93
        $(
94
            impl WideningMultiply for $ty {
95
                type Output = ($ty, $ty);
96
97
                #[inline(always)]
98
                fn wmul(self, b: $ty) -> Self::Output {
99
                    // needs wrapping multiplication
100
                    const LOWER_MASK: $scalar = !0 >> $half;
101
                    let mut low = (self & LOWER_MASK) * (b & LOWER_MASK);
102
                    let mut t = low >> $half;
103
                    low &= LOWER_MASK;
104
                    t += (self >> $half) * (b & LOWER_MASK);
105
                    low += (t & LOWER_MASK) << $half;
106
                    let mut high = t >> $half;
107
                    t = low >> $half;
108
                    low &= LOWER_MASK;
109
                    t += (b >> $half) * (self & LOWER_MASK);
110
                    low += (t & LOWER_MASK) << $half;
111
                    high += t >> $half;
112
                    high += (self >> $half) * (b >> $half);
113
114
                    (high, low)
115
                }
116
            }
117
        )+
118
    };
119
}
120
wmul_impl_large! { u128, 64 }
121
122
macro_rules! wmul_impl_usize {
123
    ($ty:ty) => {
124
        impl WideningMultiply for usize {
125
            type Output = (usize, usize);
126
127
            #[inline(always)]
128
0
            fn wmul(self, x: usize) -> Self::Output {
129
0
                let (high, low) = (self as $ty).wmul(x as $ty);
130
0
                (high as usize, low as usize)
131
0
            }
132
        }
133
    };
134
}
135
#[cfg(target_pointer_width = "16")]
136
wmul_impl_usize! { u16 }
137
#[cfg(target_pointer_width = "32")]
138
wmul_impl_usize! { u32 }
139
#[cfg(target_pointer_width = "64")]
140
wmul_impl_usize! { u64 }
141
142
/// Helper trait when dealing with scalar and SIMD floating point types.
143
pub(crate) trait FloatSIMDUtils {
144
    // `PartialOrd` for vectors compares lexicographically. We want to compare all
145
    // the individual SIMD lanes instead, and get the combined result over all
146
    // lanes. This is possible using something like `a.lt(b).all()`, but we
147
    // implement it as a trait so we can write the same code for `f32` and `f64`.
148
    // Only the comparison functions we need are implemented.
149
    fn all_lt(self, other: Self) -> bool;
150
    fn all_le(self, other: Self) -> bool;
151
    fn all_finite(self) -> bool;
152
153
    type Mask;
154
    fn finite_mask(self) -> Self::Mask;
155
    fn gt_mask(self, other: Self) -> Self::Mask;
156
    fn ge_mask(self, other: Self) -> Self::Mask;
157
158
    // Decrease all lanes where the mask is `true` to the next lower value
159
    // representable by the floating-point type. At least one of the lanes
160
    // must be set.
161
    fn decrease_masked(self, mask: Self::Mask) -> Self;
162
163
    // Convert from int value. Conversion is done while retaining the numerical
164
    // value, not by retaining the binary representation.
165
    type UInt;
166
    fn cast_from_int(i: Self::UInt) -> Self;
167
}
168
169
/// Implement functions available in std builds but missing from core primitives
170
#[cfg(not(feature = "std"))]
171
#[allow(unused)]
172
// False positive: We are following `std` here.
173
#[allow(clippy::wrong_self_convention)]
174
pub(crate) trait Float: Sized {
175
    fn is_nan(self) -> bool;
176
    fn is_infinite(self) -> bool;
177
    fn is_finite(self) -> bool;
178
}
179
180
/// Implement functions on f32/f64 to give them APIs similar to SIMD types
181
#[allow(unused)]
182
pub(crate) trait FloatAsSIMD: Sized {
183
    #[inline(always)]
184
0
    fn lanes() -> usize {
185
0
        1
186
0
    }
187
    #[inline(always)]
188
0
    fn splat(scalar: Self) -> Self {
189
0
        scalar
190
0
    }
191
    #[inline(always)]
192
0
    fn extract(self, index: usize) -> Self {
193
0
        debug_assert_eq!(index, 0);
194
0
        self
195
0
    }
196
    #[inline(always)]
197
0
    fn replace(self, index: usize, new_value: Self) -> Self {
198
0
        debug_assert_eq!(index, 0);
199
0
        new_value
200
0
    }
201
}
202
203
#[allow(unused)]
204
pub(crate) trait BoolAsSIMD: Sized {
205
    fn any(self) -> bool;
206
    fn all(self) -> bool;
207
    fn none(self) -> bool;
208
}
209
210
impl BoolAsSIMD for bool {
211
    #[inline(always)]
212
0
    fn any(self) -> bool {
213
0
        self
214
0
    }
215
216
    #[inline(always)]
217
0
    fn all(self) -> bool {
218
0
        self
219
0
    }
220
221
    #[inline(always)]
222
0
    fn none(self) -> bool {
223
0
        !self
224
0
    }
225
}
226
227
macro_rules! scalar_float_impl {
228
    ($ty:ident, $uty:ident) => {
229
        #[cfg(not(feature = "std"))]
230
        impl Float for $ty {
231
            #[inline]
232
            fn is_nan(self) -> bool {
233
                self != self
234
            }
235
236
            #[inline]
237
            fn is_infinite(self) -> bool {
238
                self == ::core::$ty::INFINITY || self == ::core::$ty::NEG_INFINITY
239
            }
240
241
            #[inline]
242
            fn is_finite(self) -> bool {
243
                !(self.is_nan() || self.is_infinite())
244
            }
245
        }
246
247
        impl FloatSIMDUtils for $ty {
248
            type Mask = bool;
249
            type UInt = $uty;
250
251
            #[inline(always)]
252
0
            fn all_lt(self, other: Self) -> bool {
253
0
                self < other
254
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::all_lt
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::all_lt
255
256
            #[inline(always)]
257
0
            fn all_le(self, other: Self) -> bool {
258
0
                self <= other
259
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::all_le
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::all_le
260
261
            #[inline(always)]
262
0
            fn all_finite(self) -> bool {
263
0
                self.is_finite()
264
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::all_finite
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::all_finite
265
266
            #[inline(always)]
267
0
            fn finite_mask(self) -> Self::Mask {
268
0
                self.is_finite()
269
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::finite_mask
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::finite_mask
270
271
            #[inline(always)]
272
0
            fn gt_mask(self, other: Self) -> Self::Mask {
273
0
                self > other
274
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::gt_mask
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::gt_mask
275
276
            #[inline(always)]
277
0
            fn ge_mask(self, other: Self) -> Self::Mask {
278
0
                self >= other
279
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::ge_mask
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::ge_mask
280
281
            #[inline(always)]
282
0
            fn decrease_masked(self, mask: Self::Mask) -> Self {
283
0
                debug_assert!(mask, "At least one lane must be set");
284
0
                <$ty>::from_bits(self.to_bits() - 1)
285
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::decrease_masked
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::decrease_masked
286
287
            #[inline]
288
0
            fn cast_from_int(i: Self::UInt) -> Self {
289
0
                i as $ty
290
0
            }
Unexecuted instantiation: <f32 as rand::distributions::utils::FloatSIMDUtils>::cast_from_int
Unexecuted instantiation: <f64 as rand::distributions::utils::FloatSIMDUtils>::cast_from_int
291
        }
292
293
        impl FloatAsSIMD for $ty {}
294
    };
295
}
296
297
scalar_float_impl!(f32, u32);
298
scalar_float_impl!(f64, u64);