C++生成不重复大随机数问题?

穿山丙 2020-09-17 10:55:55
C++有没有比较好的办法可以生成一个大随机数,范围在0~INT_MAX之间,
重点是不重复生成,直到这个范围内的每个数都被生成一遍为止?
...全文
1014 30 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
可以参考intel的数字随机数生成器的例子:https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html,这个使用了rdrand、rdseed指令,其安全性是相当高的(rdseed指令实际上是生成了真随机数,来自于芯片内置的热传感器读取的温度值的低位数字)
liups 2020-10-15
  • 打赏
  • 举报
回复
引用 5 楼 穿山丙 的回复:
[quote=引用 2 楼 lin5161678 的回复:]把你原始的问题贴出来 我感觉这个问题是你自己思考一半的成功
补充一下问题:我这里面随机写满盘的表述不是很准确,具体是给定一个起始扇区和一个操作长度,在这个起始扇区往后的操作长度内进行随机写满,保证其中的每个扇区只写一次,不重复。而这个操作长度可能是全盘大小,也就是全盘写满。 我想到的一个解决方法是用随机数引擎生成随机地址,用hash表建立中间状态,然后当随机写满70%或80%后,跳出随机,余下的直接顺序写满。 第二个就是我先生成一个配置文件,将随机生成的地址写到文件里,再让软件去读这个地址。 但这两种方法都需要建立中间过程存储扇区状态。 所以想要更好的方法。[/quote] 感觉思路不对一样。应该是遍历扇区,每个扇区写入一个随机数就可以了,是否重复真没有必要考虑的
mLee79 2020-10-14
  • 打赏
  • 举报
回复
https://en.wikipedia.org/wiki/Linear_congruential_generator 再看了一下, 不需要以素数为模,其他的数值也容易构造 长度为 M 的线性同余序列, 只是在有限域上这东西不需要咋证明偶就记串了。 系统库的 rand 就是一个线性同余序列, 如果你用 rand 都可以, 没理由构造的这个序列不可以。
  • 打赏
  • 举报
回复
引用 27 楼 mLee79 的回复:
应该是取一个比 LBA 略大的素数 p, 构造一个合适的线性同余类, 阶为 p就够了, 搞太大, 生成的数据超过范围要舍弃掉, 用起来不方便。


最接近2^48(281474976710656)的素数是281474976710677

  • 打赏
  • 举报
回复

楼上的几类素数方法,符合楼主的要求,是可以的,相当于交错,够不够随机,主要看楼主的要求了。
mLee79 2020-10-13
  • 打赏
  • 举报
回复
应该是取一个比 LBA 略大的素数 p, 构造一个合适的线性同余类, 阶为 p就够了, 搞太大, 生成的数据超过范围要舍弃掉, 用起来不方便。
  • 打赏
  • 举报
回复
目前LBA的设计是48位逻辑扇区,所以2^61-1是足够的
mLee79 2020-10-12
  • 打赏
  • 举报
回复
这写 2^31 - 1 只是它刚好是大部分系统下的 INT_MAX 而已, 你换一个更大些的有限域就是了啊, 比如 2^521 - 1 也刚好是一个素数, 你在这个 GFp 上构造一个也可以啊, 这样全宇宙的每个原子记录一个扇区也足够给个编号的。
  • 打赏
  • 举报
回复
10T硬盘扇区数没有超过2^31,但是12T就超过了,现在机械硬盘都有16T产品,SSD则已经达到64T+
千梦一生 2020-10-10
  • 打赏
  • 举报
回复
洗牌感觉很合适获得大量不重复随机数:
首先申请空间:
int array[INT_MAX] = {0,1,2,3...};
while(1)
{
int a = 取随机数做下标
int b = 取随机数做下标
array[a] 交换 array[b]
充分次数后返回
}
【但到底算不算得上随机,洗一次算不上随机,洗两次也算不上随机,那具体值为多少次时,这洗牌才算随机?确实是个问题】
赵4老师 2020-10-10
  • 打赏
  • 举报
回复
可以用位图的方法检查是否重复,参考下面:
//随机产生100000000个取值范围为[0~2的32次方减1]的数据,
//然后让用户输入一个数据,判断用户输入的数据是不是包含在前面随机产生的数据中。
//要求:当用户输入完成后,必须在1毫秒(千分之一秒)之内完成判断。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <malloc.h>
long int i;
unsigned long ul;
unsigned long *d;
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
void main() {
    d=(unsigned long *)calloc(1<<(32-5),sizeof(unsigned long));
    if (NULL==d) {
        printf("Can not calloc(%d,%d)!\n",1<<(32-5),sizeof(unsigned long));
        return;
    }
    srand(time(NULL));
    for (i=0;i<100000000;i++) {
        while (1) {
            ul=ulrand();
            if (0==(d[ul>>5]&(1lu<<(ul%32)))) {
                d[ul>>5]|=1<<(ul%32);
                break;
            }
        }
        if (0==i%1000000) printf("%09d,%10lu\n",i,ul);
    }
    while (1) {
        printf("\nInput a number:");
        fflush(stdout);
        rewind(stdin);
        if (1==scanf("%lu",&ul)) break;
    }
    if (d[ul>>5]&(1<<(ul%32))) printf("Include.\n"    );
    else                       printf("Not include.\n");
    free(d);
}
//000000000,2135468533
//001000000,2465805973
//002000000,3844079964
//003000000,1883232874
//004000000,1204697784
//005000000,4050838287
//006000000,3802081245
//007000000,1586042671
//008000000,3119931368
//009000000, 251096899
//010000000,3491239701
//011000000,3365323844
//012000000,2191846708
//013000000,1879478195
//014000000,1112631457
//015000000,1927301519
//016000000,1717332861
//017000000,2922278240
//018000000, 694854106
//019000000, 273255526
//020000000, 398518467
//021000000,3270756812
//022000000,1500289424
//023000000,1502241936
//024000000,1770380660
//025000000,3668842116
//026000000,3255869879
//027000000,1299184024
//028000000,1072990028
//029000000, 242094712
//030000000,3789344297
//031000000,2599365925
//032000000, 962754138
//033000000,2055075654
//034000000,4083452879
//035000000, 489250842
//036000000, 611455230
//037000000, 277350616
//038000000,1597410795
//039000000,3224173662
//040000000,2291446877
//041000000,2546280575
//042000000,2509145642
//043000000,2371773252
//044000000, 635555963
//045000000,2674538666
//046000000,4253690312
//047000000,2675755514
//048000000,1269320296
//049000000,3172516920
//050000000,1430265210
//051000000, 196156173
//052000000,2470825669
//053000000,2536750977
//054000000,1182829949
//055000000,3202826434
//056000000,2263336265
//057000000, 313302924
//058000000,3630264578
//059000000,1154892716
//060000000,2985304230
//061000000,1252204837
//062000000,1292076720
//063000000, 242249250
//064000000,3999999961
//065000000, 431166416
//066000000,1366947236
//067000000,1414387330
//068000000,2143784481
//069000000,3242175409
//070000000,4158065163
//071000000,1425449573
//072000000,2493600232
//073000000,1316783455
//074000000,3723170478
//075000000,3064111466
//076000000, 408557403
//077000000,3722586955
//078000000,3801652651
//079000000,3788160154
//080000000,3329440047
//081000000,1408976868
//082000000, 471838899
//083000000,2145198260
//084000000,3781081738
//085000000,3439027738
//086000000,1150808750
//087000000,2782578638
//088000000,  85604584
//089000000,2704078162
//090000000, 584840269
//091000000,3854577719
//092000000,2823653537
//093000000, 797877025
//094000000,2248017755
//095000000,1787038685
//096000000,2816548567
//097000000, 489107494
//098000000, 911680090
//099000000,3677777147
//
//Input a number:3677777147
//Include.
mLee79 2020-10-10
  • 打赏
  • 举报
回复
2^31 - 1 是个素数, 你找个合适的值做线性同余, 就可以取得 0 .... 2^31-1 之间的所有数值, 然后你找个合适的时候输出 2147483647 就可以鸟或者就直接忽略这一个数就是了, 比如 int zNEXT(int n) { return (int)((n * 2147483587LL + 1) % 2147483647); }
赵4老师 2020-10-09
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
int i;
unsigned long ul;
void main() {
    srand(time(NULL));
    for (i=0;i<10;i++) {
        ul=ulrand();
        printf("%010lu 0x%08x\n",ul,ul);
    }
}
//2337588057 0x8b54c359
//1977377429 0x75dc6295
//3607316769 0xd7034921
//0009828482 0x0095f882
//3350859779 0xc7ba1003
//0945794621 0x385fae3d
//3400869024 0xcab524a0
//3097846779 0xb8a563fb
//4287421124 0xff8cdac4
//3934016258 0xea7c5302
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}
穿山丙 2020-10-09
  • 打赏
  • 举报
回复
我明白了,您这个应该是比较方便生成大随机数吧。至于是否重复还得另动脑筋,谢谢。
赵4老师 2020-10-09
  • 打赏
  • 举报
回复
我没说保证不重复啊。 随机必然有重复,所谓“不重复的随机”实际上是洗牌。洗牌算法参考下面:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}
穿山丙 2020-10-09
  • 打赏
  • 举报
回复
引用 16 楼 赵4老师 的回复:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
unsigned __int64 ullrand(void) {
    return (
     (((unsigned __int64)ulrand())<<32)
    | ((unsigned __int64)ulrand()));
}
int i;
unsigned long ul;
unsigned __int64 ull;
void main() {
    srand(time(NULL));
    for (i=0;i<10;i++) {
        ul=ulrand();
        printf("%010lu 0x%08x\n",ul,ul);
    }
    for (i=0;i<10;i++) {
        ull=ullrand();
        printf("%020I64u 0x%016I64x\n",ull,ull);
    }
}
//3971076432 0xecb1d150
//2433428051 0x910b2a53
//1415415336 0x545d8628
//1312330759 0x4e389407
//1845758378 0x6e0409aa
//0008069933 0x007b232d
//4202720757 0xfa806df5
//2669855255 0x9f22c217
//0312068736 0x1299ca80
//2084555989 0x7c3fccd5
//03502077880857307931 0x3099e1472040ab1b
//16884702393146816355 0xea52835e19b43763
//01877364819396611730 0x1a0dbd5b45f34e92
//07839440151924835771 0x6ccb4948756a05bb
//09471412086917299176 0x8371371c820bfbe8
//04411255971577469925 0x3d37edef2f321be5
//13735846279546091130 0xbe9f876a65b7367a
//04512980766520059820 0x3ea15418aa9927ac
//15821377118299441610 0xdb90d2a9f1bb49ca
//15512417228822200185 0xd7472d480398bf79

您好,感谢您的回复,请恕我水平有限,您这个代码是如何保证它不重复的?
赵4老师 2020-10-09
  • 打赏
  • 举报
回复
赵4老师 2020-10-09
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long ulrand(void) {
    return (
     (((unsigned long)rand()<<24)&0xFF000000ul)
    |(((unsigned long)rand()<<12)&0x00FFF000ul)
    |(((unsigned long)rand()    )&0x00000FFFul));
}
unsigned __int64 ullrand(void) {
    return (
     (((unsigned __int64)ulrand())<<32)
    | ((unsigned __int64)ulrand()));
}
int i;
unsigned long ul;
unsigned __int64 ull;
void main() {
    srand(time(NULL));
    for (i=0;i<10;i++) {
        ul=ulrand();
        printf("%010lu 0x%08x\n",ul,ul);
    }
    for (i=0;i<10;i++) {
        ull=ullrand();
        printf("%020I64u 0x%016I64x\n",ull,ull);
    }
}
//3971076432 0xecb1d150
//2433428051 0x910b2a53
//1415415336 0x545d8628
//1312330759 0x4e389407
//1845758378 0x6e0409aa
//0008069933 0x007b232d
//4202720757 0xfa806df5
//2669855255 0x9f22c217
//0312068736 0x1299ca80
//2084555989 0x7c3fccd5
//03502077880857307931 0x3099e1472040ab1b
//16884702393146816355 0xea52835e19b43763
//01877364819396611730 0x1a0dbd5b45f34e92
//07839440151924835771 0x6ccb4948756a05bb
//09471412086917299176 0x8371371c820bfbe8
//04411255971577469925 0x3d37edef2f321be5
//13735846279546091130 0xbe9f876a65b7367a
//04512980766520059820 0x3ea15418aa9927ac
//15821377118299441610 0xdb90d2a9f1bb49ca
//15512417228822200185 0xd7472d480398bf79

赵4老师 2020-10-09
  • 打赏
  • 举报
回复
引用 14 楼 早打大打打核战争 的回复:
老赵这个满足 不重复 大 随机数么
我一贯保持给渔网不给鱼的作风。
  • 打赏
  • 举报
回复
老赵这个满足 不重复 大 随机数么
加载更多回复(12)

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧