【问题标题】:How to implement an unbiased random method for signed integers within a range?如何为范围内的有符号整数实现无偏随机方法?
【发布时间】:2021-07-07 18:29:08
【问题描述】:

我一直在为随机数生成创建一个精简的库,并且一直在努力生成一个范围内的有符号整数。

无符号整数很简单,我已经实现了 Lemire 的去偏整数乘法方法。但是,它不容易扩展到有符号整数:

impl<R: Rng> RandomRange<R> for u64 {
    fn random_range<B: RangeBounds<Self>>(r: &mut R, bounds: B) -> Self {
        const BITS: u128 = core::mem::size_of::<u64>() as u128 * 8;
        let lower = match bounds.start_bound() {
            Bound::Included(lower) => *lower,
            Bound::Excluded(lower) => lower.saturating_add(1),
            Bound::Unbounded => <u64>::MIN,
        };
        let upper = match bounds.end_bound() {
            Bound::Included(upper) => upper.saturating_sub(lower).saturating_add(1),
            Bound::Excluded(upper) => upper.saturating_sub(lower),
            Bound::Unbounded => <u64>::MAX,
        };
        let mut value = Self::random(r);
        let mut m = (upper as u128).wrapping_mul(value as u128);
        if (m as u64) < upper {
            let t = (!upper + 1) % upper;
            while (m as u64) < t {
                value = Self::random(r);
                m = (upper as u128).wrapping_mul(value as u128);
            }
        }
        (m >> BITS) as u64 + lower
    }
}

如何在有符号整数的最小/最大范围内实现大部分去偏随机数生成?

【问题讨论】:

  • 对于那些不想实现它的人,另请参阅How to generate a random Rust integer in a range without introducing bias?。
  • 另见我的部分:RNDINTRANGE.
  • 不清楚将算法转换为有符号数字有什么困难。您知道范围的宽度和范围的开始。你能不生成一个宽度相同的无符号范围,然后将结果值移到开头吗?
  • @Shepmaster:等等,你是对的......给我一点,我会试着自己回答这个问题。
  • 我现在正在为整个 i32-u32 转换而苦苦挣扎,呃。

标签: random rust


【解决方案1】:

好的,我开始工作了。我使用 &lt;$type&gt;::MAX / 2 + 1 周围的环绕添加将有符号整数的范围映射到无符号整数。

fn random_range<B: RangeBounds<Self>>(r: &mut R, bounds: B) -> Self {
    const SIGNED_MAPPING: u64 = <u64>::MAX / 2 + 1;
    let lower = match bounds.start_bound() {
        Bound::Included(lower) => *lower,
        Bound::Excluded(lower) => lower.saturating_add(1),
        Bound::Unbounded => <i64>::MIN
    };
    let upper = match bounds.end_bound() {
        Bound::Included(upper) => *upper,
        Bound::Excluded(upper) => upper.saturating_sub(1),
        Bound::Unbounded => <i64>::MAX,
    };
    let lower = (lower as u64).wrapping_add(SIGNED_MAPPING);
    let upper = (upper as u64).wrapping_add(SIGNED_MAPPING);
    assert!(upper >= lower, "{} >= {}", upper, lower);
    <u64>::random_range(r, lower..=upper).wrapping_add(SIGNED_MAPPING) as i64
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-21
    • 2020-07-18
    • 2012-07-30
    • 2014-05-08
    • 2023-04-07
    • 2022-11-18
    相关资源
    最近更新 更多