在Rust中生成给定位大小的随机数。

huangapple go评论81阅读模式
英文:

generate a random number with given bit size in Rust

问题

我正在尝试使用Rug在Rust中生成任意位数的随机数。我创建了一个像这样的函数:

fn bit_str(bitlen: usize) -> String {
    let vs = vec!['0','1'];
    let mut nums = vec!['0'; bitlen];
    for i in 0..bitlen {
        nums[i] = *vs.choose(&mut rand::thread_rng()).unwrap();
    }
    return nums.into_iter().collect::<String>();
}
let bin = bit_str(1_000_000);
let mut random_number = Integer::new();
random_number.assign(Integer::parse_radix(&bin, 2).unwrap());

但这很慢。在我的环境中,生成1百万位的100个随机数需要30秒。有没有办法更快地生成这样的随机数?

英文:

I am trying to generate a random number with aribitorary bit size in Rust using Rug. I create a function like this:

fn bit_str(bitlen: usize) -&gt; String {
    let vs = vec![&#39;0&#39;,&#39;1&#39;];
    let mut nums = vec![&#39;0&#39;; bitlen];
    for i in 0..bitlen {
        nums[i] = *vs.choose(&amp;mut rand::thread_rng()).unwrap();
    }
    return nums.into_iter().collect::&lt;String&gt;();
}
let bin = bit_str(1_000_000);
let mut random_number = Integer::new();
random_number.assign(Integer::parse_radix(bin,2).unwrap());

But this is slow. In my environment, it took 30 seconds to generate 100 random numbers with 1m bits. Is there any way to generate such random numbers faster?

答案1

得分: 3

这个答案类似于apilat的答案,但使用了 rug 并生成尽可能大的块(最多 32 位,这是 rug::rand::RandState::bits 支持的最大值):

/*
[dependencies]
rug = "*"
*/

fn rand(mut bits: u32) -> rug::Integer {
    let mut rand = rug::rand::RandState::new();

    let mut res = rug::Integer::with_capacity(bits as usize);

    while bits > 0 {
        let generate = bits.min(32);

        res = (res << generate) + rand.bits(generate);
        
        bits -= generate;
    }

    res
}

fn main() {
    println!("{:b}", rand(1_000_000));
}

[Rustexplorer.](https://www.rustexplorer.com/b#%2F*%0A%5Bdependencies%5D%0Arug%20%3D%20%22*%22%0A*%2F%0A%0Afn%20rand(mut%20bits%3A%20u32)%20-%3E%20rug%3A%3AInteger%20%7B%0A%20%20%20%20let%20mut%20rand%20%3D%20rug%3A%3Arand%3A%3ARandState%3A%3Anew()%3B%0A%0A%20%20%20%20let%20mut%20res%20%3D%20rug%3A%3AInteger%3A%3Awith_capacity(bits%20as%20usize)%3B%0A%0A%20%20%20%20while%20bits%20%3E%200%20%7B%0A%20%20%20%20%20%20%20%20let%20generate%20%3D%20bits.min(32)%3B%0A%0A%20%20%20%20%20%20%20%20res%20%3D%20(res%20%3C%3C%20generate)%20%2B%20rand.bits(generate)%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20bits%20-%3D%20generate%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20res%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!("{:b}", rand(1_000_000));%0A%7D)

英文:

This answer is akin to apilat's, but uses rug and generates as big of chunks as possible (at most 32 bits, which is the maximum rug::rand::RandState::bits supports):

/*
[dependencies]
rug = &quot;*&quot;
*/

fn rand(mut bits: u32) -&gt; rug::Integer {
    let mut rand = rug::rand::RandState::new();

    let mut res = rug::Integer::with_capacity(bits as usize);

    while bits &gt; 0 {
        let generate = bits.min(32);

        res = (res &lt;&lt; generate) + rand.bits(generate);
        
        bits -= generate;
    }

    res
}

fn main() {
    println!(&quot;{:b}&quot;, rand(1_000_000));
}

Rustexplorer.

答案2

得分: 1

在一般情况下,直接使用整数比使用字符串然后转换要快得多。
将比特 b 追加到现有数字 x 的操作可以通过将 x 向左位移一位,然后加上 b 来实现:(x << 1) + b。这是下面实现的原理。

我找不到你的 Integer 类型是从哪里来的,所以示例(playground)使用了 num::BigInt

你可以通过以更大的块生成比特(例如 32 或 64 位)来使这段代码运行得更快,尽管会增加一些实现复杂性。

use num::BigInt;
use rand::{Rng, thread_rng};

fn randint(bits: usize) -> BigInt {
    let mut rng = thread_rng();
    let mut x = BigInt::default();
    for _ in 0..bits {
        x <<= 1;
        x += rng.gen_range(0..=1);
    }
    x
}

fn main() {
    let x = randint(10);
    let y = randint(1000);
    println!("{x}");
    println!("{y}");
}
英文:

In general, working with integers directly is much faster than working with strings and then converting.
The operation of appending a bit b at the end of an existing number x
can be implemented by bit-shifting x one to the left and then adding b: (x &lt;&lt; 1) + b.
This is the principle behind the implementation below.

I couldn't figure out where your Integer type comes from so the example (playground) uses num::BigInt instead.
You could make this code even faster by generating bits in larger chunks (for example 32 or 64 bits) at the cost of some implementation complexity.

use num::BigInt;
use rand::{Rng, thread_rng};

fn randint(bits: usize) -&gt; BigInt {
    let mut rng = thread_rng();
    let mut x = BigInt::default();
    for _ in 0..bits {
        x &lt;&lt;= 1;
        x += rng.gen_range(0..=1);
    }
    x
}

fn main() {
    let x = randint(10);
    let y = randint(1000);
    println!(&quot;{x}&quot;);
    println!(&quot;{y}&quot;);
}

huangapple
  • 本文由 发表于 2023年6月11日 21:33:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76450713.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定