C/C++生成随机数

随机数的用途

  • 单元测试
  • 游戏抽奖
  • 仿真及安全
  • and so on

伪随机数:c++产生随机数

生成器(engine):能够产生离散的等可能分布数值

- 如线性同余法(linear_congruential_engine)
- 梅森旋转法(meraenne_twister_engine)
- 滞后Fibonacci(substract_with_carry_engine)

分布器(distribution):能够把generator均匀分布值映射到其他常见分布

- 如均匀分布(unifor)
    - uniform_int_distribution 整数均匀分布
    - uniform_real_distribution 浮点数均匀分布
- 正态分布(normal) (仅有yes/no两种结果,概率一个p,一个1-p)
- 二项分布(binorial)
- 泊松分布(poisson)
#include <random>

default_random_engine e{}; // default engine
// distribution将产生的随机数映射到整数1..6
uniform_int_distribution<int> one_to_six{1, 6};
// 产生一个符合指定规则的随机数
#include <random>

int x = u(e); 

auto dice{bind(u, e)};
int y = dice();
#include <random>

// 产生随机数
int rand_int(int low, int high)
{
    using namespace std;
    static default_random_engine e;
    using Dist = uniform_int_distribution<int>;
    static Dist u{};
    return u(e, Dist::param_type{low, high});
}
#include <random>
#include <iostream>
std::mt19937 gen;
void  test_random(){
    std::uniform_real_distribution<> d(4.5, 5.2);
    for (int i = 0; i < 20; ++i)
        std::cout << d(gen) << std::endl;
    getchar();
}

int main(int argc, char **argv){
    return test_random();
}
// output
4.59483
5.08451
5.17821
4.65472
4.71572
4.88305
4.63187
5.19502
5.19752
5.17739
5.00809
5.18678
4.5769
5.05867
4.70792
4.50335
4.57873
4.94783
5.1149
4.85256

伪随机数:C语言实现随机数

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
// Maximum value that can be returned by the rand function:
#define RAND_MAX 0x7fff

_ACRTIMP void __cdecl srand(_In_ unsigned int _Seed);

_Check_return_ _ACRTIMP int __cdecl rand(void);
*/
void show() {
  printf("rand()------------\n");
  for (int i = 0; i < 10; ++i)
    printf("%d |", rand());
  printf("\n");
}
void show_range(int a, int b) { // 固定范围的随机数
  for (int i = 0; i < 10; ++i)
    printf("%d |", rand() % (b - a) + a);
  printf("\n");
}
void func() {
  printf("-------test start------------\n");
  show(); /*rand() == rand(1)*/
  printf("-------srand(1)--------------\n");
  srand(1);
  show();
  printf("-------srand(11111)----------\n");
  srand(11111);
  show();
  printf("-------srand(time(NULl))-----\n");
  srand(time(NULL));
  show();
  printf("-------test end--------------\n");
  return;
}
-------test start------------
rand()------------
41 |18467 |6334 |26500 |19169 |15724 |11478 |29358 |26962 |24464 |
-------srand(1)--------------
rand()------------
41 |18467 |6334 |26500 |19169 |15724 |11478 |29358 |26962 |24464 |
-------srand(11111)----------
rand()------------
3554 |26670 |1503 |15804 |24395 |27484 |20568 |13190 |2698 |7943 |
-------srand(time(NULl))-----
rand()------------
16547 |21195 |9007 |7453 |12018 |30665 |27311 |4207 |12232 |15391 |
-------test end--------------

  1. rand函数产生随机数(收获果实)

    int rand();

    头文件为<stdlib.h>

  2. srand设置随机数种子(播种种子)

    void srand( unsigned seed );

  3. 不设置种子值时,默认种子为1,即srand(1)

  4. 为保证每个 程序每次产生的随机数不同,使用前可以参考使用时间作为种子

    srand(time(NULL))

    添加头文件<time.h>

  5. rand不是线程安全的函数(原则是每个线程的种子不一致)

    1. posix的替代方案时rand_r(int *seed)
    2. 可以使用线程id作为种子来处理

真随机数数

C语言中rand()函数生成的数实际上是一个伪随机序列,这意味着每次程序运行时,得到的序列是预先确定好的,因此并不能真正满足安全性要求。

C++标准库中的随机数生成器(头文件中的相关类)通常提供的是伪随机数生成器(pseudo-random number generator,PRNG)。
PRNG是一种基于确定性算法的随机数生成器,它通过一个起始种子(或者称为随机种子)生成一个序列,看起来是随机的。然而,这个序列实际上是根据算法计算得出的,因此在给定相同的种子的情况下,生成的随机数序列将是可预测的。
在C++标准库中,std::rand()函数和相关的随机数生成器类(如std::default_random_engine)都是基于PRNG的。它们提供的随机数序列具有良好的统计特性,但不适合用于需要高度安全性的场景,如密码学或加密算法。

如果你需要生成真正的随机数,可以使用操作系统提供的随机数生成器。

  1. 在Linux和Unix系统中,可以使用/dev/random或/dev/urandom设备来获取真随机数。
  2. 在Windows系统中,可以使用CryptGenRandom()函数。这些方法利用了操作系统的硬件和环境熵池来生成真正的随机数。
  3. 使用第三方库,如Crypto++或Botan,它们提供了更安全和真随机的随机数生成功能

使用/dev/urandom生成真随机数

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE* urandom = fopen("/dev/urandom", "r");
    if (urandom == NULL) {
        printf("无法打开 /dev/urandom 设备\n");
        return 1;
    }

    unsigned int random_number;
    fread(&random_number, sizeof(random_number), 1, urandom);

    printf("生成的随机数:%u\n", random_number);

    fclose(urandom);
    return 0;
}

使用CryptGenRandom生成真随机数

#include <iostream>
#include <Windows.h>
#include <wincrypt.h>

int main() {
    HCRYPTPROV hCryptProv;
    BYTE randomBytes[4];

    if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
        std::cerr << "无法获取加密服务提供者句柄" << std::endl;
        return 1;
    }

    if (!CryptGenRandom(hCryptProv, sizeof(randomBytes), randomBytes)) {
        std::cerr << "无法生成随机数" << std::endl;
        CryptReleaseContext(hCryptProv, 0);
        return 1;
    }

    // 将随机数打印到控制台
    for (int i = 0; i < sizeof(randomBytes); ++i) {
        printf("%02x ", randomBytes[i]);
    }
    std::cout << std::endl;

    CryptReleaseContext(hCryptProv, 0);
    return 0;
}

posted @ 2021-11-04 10:01  flxx  阅读(413)  评论(0编辑  收藏  举报