【问题标题】:How do I generate random numbers without rand() function?如何在没有 rand() 函数的情况下生成随机数?
【发布时间】:2011-11-28 00:14:55
【问题描述】:

我想生成介于 0 和某个整数之间的(伪)随机数。我不介意它们不是太随机。我可以访问一天中的当前时间,但不能访问 rand 函数。谁能想到一个足够强大的方法来生成这些?也许,从一天中的某个时间丢弃一些位并取模我的整数或其他什么?

我正在使用 c。

【问题讨论】:

  • 这听起来像是家庭作业。如果是,则应使用“作业”标签对其进行标记。
  • 如果您可以访问 google.com,请尝试搜索:“随机数生成器”。
  • 为什么不直接阅读/dev/random?或者使用 xkcd 方法。
  • 那么是什么阻止您简单地使用random()?
  • rand() 通常非常简单地实现(使用种子的简单乘法然后混合)......它通常大约是一行。谷歌一下就行了。

标签: c random


【解决方案1】:

如果您想要一个超简单的伪随机生成器,您可以使用Linear Feedback shift Register。

维基百科文章有一些代码 sn-ps 供您查看,但基本上 16 位生成器的代码看起来像这样(从那个页面轻轻按摩...)

  unsigned short lfsr = 0xACE1u;
  unsigned bit;

  unsigned rand()
  {
    bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
    return lfsr =  (lfsr >> 1) | (bit << 15);
  }

【讨论】:

  • 正是我需要的!一个非常简单优雅的解决方案
  • 这行得通。当您需要不同的号码流时,只需更改 lfsr
【解决方案2】:

对于“不太随机”的整数,您可以从当前 UNIX 时间开始,然后使用递归公式 r = ((r * 7621) + 1) % 32768;。在第 n 次迭代后,0(含)和 M(不含)之间的第 n 个随机整数将是 r % M。

这称为线性同余生成器。

递归公式是 bzip2 在其快速排序实现中用来选择枢轴的。我不知道其他用途,但它对这个特定的用途非常有效......

【讨论】:

    【解决方案3】:

    看看自己实现一个伪随机生成器(rand() 的“内部”是什么),例如,Mersenne twister 备受推崇。

    【讨论】:

      【解决方案4】:

      执行此操作的唯一“稳健”(不易预测)方法是编写您自己的伪随机数生成器并使用当前时间为其播种。必填维基百科链接:http://en.wikipedia.org/wiki/Pseudorandom_number_generator

      【讨论】:

        【解决方案5】:
        #include <chrono>
        
        int get_rand(int lo, int hi) {
            auto moment = std::chrono::steady_clock::now().time_since_epoch().count();
            int num = moment % (hi - lo + 1);
            return num + lo;
        }
        

        【讨论】:

        • 似乎是对 C 问题的 C++ 答案。
        【解决方案6】:

        你可以在这里获得“小梅森捻线机”:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html

        它是纯 C 语言,使用简单。例如。只是使用时间:

        #include "tinymt32.h"
        // And if you can't link:
        #include "tinymt32.c"
        
        #include <time.h>
        #include <stdio.h>
        
        int main(int argc, const char* argv[])
        {
            tinymt32_t state;
            uint32_t seed = time(0);
        
            tinymt32_init(&state, seed);
        
            for (int i=0; i<10; i++)
                    printf("random number %d: %u\n", i, (unsigned int)tinymt32_generate_uint32(&state));
        }
        

        【讨论】:

        • 我无法使用任何其他库!
        • can't 对你来说是什么意思?包含另一个#include "tinymt32.c" 怎么样?
        【解决方案7】:

        下面提供了与 ranges 一起使用的最小且简单的 random generator,并提供了完整的工作示例。

        unsigned int MyRand(unsigned int start_range,unsigned int end_range)
          {
            static unsigned int rand = 0xACE1U; /* Any nonzero start state will work. */
        
            /*check for valid range.*/
            if(start_range == end_range) {
                return start_range;
            }
        
            /*get the random in end-range.*/
            rand += 0x3AD;
            rand %= end_range;
        
            /*get the random in start-range.*/
            while(rand < start_range){
                rand = rand + end_range - start_range;
            }
        
            return rand;
          }
        
        int main(void)
        {
            int i;
            for (i = 0; i < 0xFF; i++)
            {
            printf("%u\t",MyRand(10,20));
            }
            return 0;
        }
        

        【讨论】:

          【解决方案8】:

          如果您生成数字的速度不是太快 (*1) 并且您的上限足够低 (*2) 并且您的“一天中的时间”包括纳秒,那么只需使用这些纳秒。

          #include <stdio.h>
          #include <stdlib.h>
          #include <time.h>
          
          int nanorand(void) {
              struct timespec p[1];
              clock_gettime(CLOCK_MONOTONIC, p);
              return p->tv_nsec % 1000;
          }
          
          int main(void) {
              int r, x;
              for (;;) {
                  r = nanorand();
                  do {
                      printf("please type %d (< 50 quits): ", r);
                      fflush(stdout);
                      if (scanf("%d", &x) != 1) exit(EXIT_FAILURE);
                  } while (x != r);
                  if (r < 50) break;
              }
              puts("");
              return 0;
          }
          

          还有一个示例运行...

          请输入 769(

          (*1) 如果您以交互方式使用它们,一次一个
          (*2) 如果您想要最大约 1000 的数字

          【讨论】:

            【解决方案9】:
            import java.io.*;
            public class random{
            public static class p{
            
            }
            static long reg=0;
            static long lfsr()
            {
                if(reg==0)
                {
                    reg=145896027340307l;
                }
                long bit=(reg>>0^reg>>2^reg>>3^reg>>5)&1;
                reg=reg>>1|bit<<62;
                return reg;
            }
            static long getRand()
            {
                String s=String.valueOf(new p());
                //System.out.println(s);
                long n=0;
                lfsr();
                for(int i=0;i<s.length();i++)
                {
                    n=n<<8|+s.charAt(i);
                }
                System.out.print(n+" "+System.currentTimeMillis()+" "+reg+" ");
                n=n^System.currentTimeMillis()^reg;
                return n;
            }
            public static void main(String args[])throws IOException
            {
                for(int i=0;i<400;i++)
                {
                    System.out.println(getRand());
                }
            }
            

            }

            这是一个随机数生成器,可以保证序列永远不会重复。我已将时间与对象值(由 java 随机放置)与 LFSR 配对。

            优点:

            • 序列不会重复自己
            • 每次运行的序列都是新的

            缺点:

            • 仅与 java 兼容。在 C++ 中,每次运行时创建的新对象都是相同的。
            • 但是时间和 LFSR 参数会产生足够的随机性
            • 它比大多数 PRNG 慢,因为每次需要数字时都需要创建一个对象

            【讨论】:

              【解决方案10】:
              #include<time.h>
              int main(){
              int num;
              time_t sec;
              sec=time(NULL);
              printf("Enter the Range under which you want Random number:\n");
              scanf("%d",&num);
              if(num>0)
              {
              for(;;)
              {
              sec=sec%3600;
              if(num>=sec)
              {
              printf("%ld\n",sec);
              break;
              }
              sec=sec%num;
              }
              }
              else
              {
              printf("Please Enter Positive Value!\n");
              }
              return 0;
              }
              

              【讨论】:

              • 您至少应该应用一些适当的缩进。添加一个解释你的实现是如何工作的会很有用。 sec=sec%3600; 也是错误的。为什么要使用循环?该范围在第一次迭代后应用。您可以立即执行此操作。
              【解决方案11】:
              #include<stdio.h>
              #include<conio.h>
              #include<stdlib.h>
              int main()
              {
              unsigned int x,r,i;
              // no of random no you want to generate
              scanf("%d",&x);
              // put the range of random no 
              scanf("%d",&r);
              unsigned int *a=(unsigned int*)malloc(sizeof(unsigned int)*x);
              for(i=0;i<x;i++)
              printf("%d ",(a[i]%r)+1);   
              free(a);
              getch();
              return 0;
              }
              

              【讨论】:

              【解决方案12】:

              不总是返回相同值的最简单的随机数生成器之一:

              uint16_t simpleRand(void)
                {
                  static uint16_t r = 5531; //dont realy care about start value
                  r+=941; //this value must be relative prime to 2^16, so we use all values
                  return r;
                }  
              

              如果您不希望序列始终以相同的值开始,您可以花时间设置开始值。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-09-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多