随机函数总是返回相同的结果,尽管种子不同

时间:2013-03-04 18:11:34

标签: cobol gnucobol

我正在尝试创建一个随机数生成器(稍后将一些随机数转换为[A-Z]字符)。我有随机生成器的主要部分工作,但我不断收到相同的随机结果0.6734141422

我面临的另一个问题:我的程序编译太快的一半时间。因为我以毫秒为单位使用当前日期,所以我的程序快速编译将意味着同一种子被赋予RANDOM函数。我一直在考虑简单地添加一个计数器,在将每个种子应用到RANDOM之前将其除以计数器。这还不够,还是有更优雅的解决方案?

有人可以向我解释为什么即使应用了不同的种子值,我总是会收到相同的随机结果吗?每次执行程序时都会得到这个结果。

我正在使用PerCobol编译器,据我所知,它与OpenCobol兼容。

总结一下:

  • 我应该如何克服平等的种子?
  • 为什么我会收到不同种子的相同随机结果?

    000100 IDENTIFICATION DIVISION.
    000200 PROGRAM-ID. RandomTest.
    
    ENVIRONMENT DIVISION.  
    
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 RANDOMRESULT PIC S9V9(10).
    
       01 WS-CURRENT-DATE-DATA.
        05 WS-CURRENT-DATE.
          10 WS-CURRENT-YEAR    PIC 9(04).
          10 WS-CURRENT-MONTH   PIC 9(02).
          10  WS-CURRENT-DAY    PIC 9(02).
        05  WS-CURRENT-TIME.
      10  WS-CURRENT-HOURS      PIC 9(02).
      10  WS-CURRENT-MINUTE     PIC 9(02).
      10  WS-CURRENT-SECOND     PIC 9(02).
      10  WS-CURRENT-MILLISECONDS   COMP-2.
    05  WS-DIFF-FROM-GMT        PIC S9(04).
    
       PROCEDURE DIVISION.
       PRGRM.
    
       PERFORM 4 TIMES
        MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-DATA
        COMPUTE RANDOMRESULT = FUNCTION RANDOM (WS-CURRENT-MILLISECONDS)
        DISPLAY "Seed value: " WS-CURRENT-MILLISECONDS UPON SYSOUT
        DISPLAY "Random result: " RANDOMRESULT UPON SYSOUT
       END-PERFORM
    
       STOP RUN.
    

示例输出:

Seed value: 8.222829361429599E-67
Random result: 0.6734141422
Seed value: 8.964670591567083E-67
Random result: 0.6734141422
Seed value: 9.335591206635825E-67
Random result: 0.6734141422
Seed value: 9.335591206635825E-67
Random result: 0.6734141422

如果您有解决原始问题的建议(创建一个由字母数字字符组成的随机密码),我也很高兴听到它。

编辑: 通过省略种子,两个问题立即得到解决。更多背后的结论可以在下面的评论中找到。如果有人解释为什么不同的种子仍会产生相同的价值,我会很高兴听到它!

3 个答案:

答案 0 :(得分:2)

是的,您的种子必须是整数,因此您不能使用COMP-2。种子不需要是一个特定的大小,只需一个整数,你可能会使它变得非常大。

程序编译所需的时间与任何事情无关。

您应该在第一次调用函数时指定SEED。之后,使用零。这将遵循“伪随机”序列。你不需要每次“播种”,所以不必担心毫秒。

您应该始终输出种子,以便稍后重新生成序列。使用时间变得棘手,因此请使用包含种子的参数或单个记录文件。

答案 1 :(得分:1)

this post开始,似乎RANDOM函数需要将32位整数作为种子。但是,您将WS-CURRENT-MILLISECONDS声明为COMP-2浮点数(在其他语言中,为64位双精度数。)

我想这会使它成为种子的无效参数,因此使用默认种子值0,或者只使用double的第一个或最后32位,所以你基本上得到{{3对于你正在尝试的数字,这是相同的。

如果发生了第一件事,尝试使用0作为种子,我想你会得到相同的输出。在任何情况下,您都可以尝试使用一些不同的整数播种,看看会发生什么。

答案 2 :(得分:0)

以下是生成随机数的一些源代码,希望这会有所帮助。

   IDENTIFICATION DIVISION.
   PROGRAM-ID.  RANDGEN as "ConsoleApplication2.RANDGEN".
   AUTHOR.  Myron D Denson.
   DATE-COMPILED.
  * ************************************************************** 
  *  SUBROUTINE TO GENERATE RANDOM NUMBERS THAT ARE GREATER THAN
  *    ZERO AND LESS OR EQUAL TO THE RANDOM NUMBERS NEEDED WITH NO
  *    DUPLICATIONS.  (CALL "RANDGEN" USING RANDGEN-AREA.)
  *     
  *    FORMULA CYCLES THROUGH EVERY NUMBER OF 2X2 ONLY ONCE. 
  *    RANDOM-NUMBERS FROM 1 TO RANDOM-NUMBERS-NEEDED ARE CREATED 
  *    AND PASSED BACK TO YOU.
  *
  *  RULES TO USE RANDGEN:
  *
  *    RANDOM-NUMBERS-NEEDED > ZERO 
  *     
  *    COUNT-OF-ACCESSES MUST = ZERO FIRST TIME USED.
  *         
  *    RANDOM-NUMBER = ZERO, WILL BUILD A SEED FOR YOU
  *    WHEN COUNT-OF-ACCESSES IS ALSO = 0 
  *     
  *    RANDOM-NUMBER NOT = ZERO, WILL BE NEXT SEED FOR RANDGEN
  *    YOU CAN PASS RANDGEN YOUR OWN RANDOM-NUMBER SEED
  *     THE FIRST TIME YOU USE RANDGEN.
  *     
  *    BY PLACING A NUMBER IN RANDOM-NUMBER FIELD
  *      THAT FOLLOWES THESE SIMPLE RULES:
  *        IF COUNT-OF-ACCESSES = ZERO AND 
  *        RANDOM-NUMBER > ZERO. 
  *    
  *    YOU CAN PICK THE SEED OR YOU CAN LET RANDGEN BUILD A SEED FOR YOU.
  *
  *       IF YOU PICK A SEED < RANDON-NUMBERS-NEEDED IT WILL BECOME THE LAST
  *          RANDON-NUMBER YOU RECEIVE BACK.
  *       IF SEED > RANDON-NUMBERS-NEEDED LAST NUMBER COULD BE ANYTHING.         
  *     
  *      THAT FOLLOWES THESE SIMPLE RULES:
  *        IF COUNT-OF-ACCESSES = ZERO AND 
  *        RANDOM-NUMBER = ZERO AND 
  *        RANDOM-NUMBER-NEEDED > ZERO  
  *         
  *     TO INSURING A DIFFERENT PATTERN OF RANDOM NUMBERS
  *        A LOW-RANGE AND HIGH-RANGE IS USED TO BUILD
  *        RANDOM NUMBERS.
  *        COMPUTE LOW-RANGE =
  *             ((SECONDS + HOURS + MINUTES + MS) * 1753).           
  *        A HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE
  *        AFTER RANDOM-NUMBER-BUILT IS CREATED 
  *        AND IS BETWEEN LOW AND HIGH RANGE
  *        RANDUM-NUMBER = RANDOM-NUMBER-BUILT - LOW-RANGE
  *               
  * **************************************************************         
   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
   DATA DIVISION.
   FILE SECTION.
   WORKING-STORAGE SECTION.
   01  WORK-AREA.
       05  X2-POWER                     PIC 9      VALUE 2. 
       05  2X2                          PIC 9(12)  VALUE 2.
       05  RANDOM-NUMBER-BUILT          PIC 9(12)  COMP.
       05  FIRST-PART                   PIC 9(12)  COMP.
       05  NOT-USED-NUMBER              PIC 9(12)  COMP.
       05  LOW-RANGE                    PIC 9(12)  VALUE ZERO.
       05  HIGH-RANGE                   PIC 9(12)  VALUE ZERO.
       05  YOU-PROVIDE-SEED             PIC X      VALUE SPACE.
       05  RUN-AGAIN                    PIC X      VALUE SPACE.
       05  PAUSE-FOR-A-SECOND           PIC X      VALUE SPACE.   
   01  SEED-TIME.
       05  HOURS                        PIC 99.
       05  MINUTES                      PIC 99.
       05  SECONDS                      PIC 99.
       05  MS                           PIC 99. 
  *
  * LINKAGE SECTION.
  *  Not used during testing  
   01  RANDGEN-AREA.
       05  COUNT-OF-ACCESSES            PIC 9(12) VALUE ZERO.
       05  RANDOM-NUMBERS-NEEDED        PIC 9(12) VALUE ZERO.
       05  RANDOM-NUMBER                PIC 9(12) VALUE ZERO.
       05  RANDOM-MSG                   PIC X(60) VALUE SPACE.
  *    
  * PROCEDURE DIVISION USING RANDGEN-AREA.
  * Not used during testing 
  *  
   PROCEDURE DIVISION.
   100-RANDGEN-EDIT-HOUSEKEEPING.
       MOVE SPACE TO RANDOM-MSG. 
       IF RANDOM-NUMBERS-NEEDED = ZERO
         DISPLAY 'RANDOM-NUMBERS-NEEDED ' NO ADVANCING
         ACCEPT RANDOM-NUMBERS-NEEDED.
       IF RANDOM-NUMBERS-NEEDED NOT NUMERIC 
         MOVE 'RANDOM-NUMBERS-NEEDED NOT NUMERIC' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF RANDOM-NUMBERS-NEEDED = ZERO
         MOVE 'RANDOM-NUMBERS-NEEDED = ZERO' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF COUNT-OF-ACCESSES NOT NUMERIC
         MOVE 'COUNT-OF-ACCESSES NOT NUMERIC' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF COUNT-OF-ACCESSES GREATER THAN RANDOM-NUMBERS-NEEDED
         MOVE 'COUNT-OF-ACCESSES > THAT RANDOM-NUMBERS-NEEDED' TO RANDOM-MSG
           GO TO 900-EXIT-RANDGEN.
       IF YOU-PROVIDE-SEED = SPACE AND RANDOM-NUMBER = ZERO
         DISPLAY 'DO YOU WANT TO PROVIDE SEED  Y OR N: '
           NO ADVANCING
           ACCEPT YOU-PROVIDE-SEED.  
       IF RANDOM-NUMBER = ZERO AND
          (YOU-PROVIDE-SEED = 'Y' OR 'y')
         DISPLAY 'ENTER SEED ' NO ADVANCING
         ACCEPT RANDOM-NUMBER. 
       IF RANDOM-NUMBER NOT NUMERIC
         MOVE 'RANDOM-NUMBER NOT NUMERIC' TO RANDOM-MSG
         GO TO 900-EXIT-RANDGEN.
   200-RANDGEN-DATA-HOUSEKEEPING.      
       MOVE FUNCTION CURRENT-DATE (9:8) TO SEED-TIME.
       IF COUNT-OF-ACCESSES = ZERO
         COMPUTE LOW-RANGE =
                ((SECONDS + HOURS + MINUTES + MS) * 1753).
       COMPUTE RANDOM-NUMBER-BUILT = RANDOM-NUMBER + LOW-RANGE.  
       COMPUTE HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE.
       MOVE X2-POWER TO 2X2.             
   300-SET-2X2-DIVISOR.
       IF 2X2 < (HIGH-RANGE + 1) 
          COMPUTE 2X2 = 2X2 * X2-POWER
           GO TO 300-SET-2X2-DIVISOR.    
  * *********************************************************         
  *  IF FIRST TIME THROUGH AND YOU WANT TO BUILD A SEED.    *
  * ********************************************************* 
       IF COUNT-OF-ACCESSES = ZERO AND RANDOM-NUMBER = ZERO
          COMPUTE RANDOM-NUMBER-BUILT =
                ((SECONDS + HOURS + MINUTES + MS) + HIGH-RANGE).
  * *********************************************     
  *    END OF BUILDING A SEED IF YOU WANTED TO  * 
  * ********************************************* 
  * *******************************************************
  * THE NEXT 4 LINE OF CODE ARE FOR TESTING  ON CONSOLE   *  
  * *******************************************************            
  *    IF COUNT-OF-ACCESSES = ZERO        
  *      DISPLAY 'SEED TIME ' SEED-TIME 
  *            ' RANDOM-NUMBER-BUILT ' RANDOM-NUMBER-BUILT 
  *            ' LOW-RANGE  ' LOW-RANGE.          
  * ***************************************************
  * THIS PROCESS IS WHERE THE RANDOM-NUMBER IS BUILT  *  
  * ***************************************************   
   400-RANDGEN-FORMULA.
       COMPUTE FIRST-PART = (5 * RANDOM-NUMBER-BUILT) + 7.
       DIVIDE FIRST-PART BY 2X2 GIVING NOT-USED-NUMBER 
         REMAINDER RANDOM-NUMBER-BUILT. 
       IF RANDOM-NUMBER-BUILT > LOW-RANGE AND
          RANDOM-NUMBER-BUILT < (HIGH-RANGE + 1)
         GO TO 600-RANDGEN-CLEANUP.
       GO TO 400-RANDGEN-FORMULA.
  * *********************************************     
  *    GOOD RANDOM NUMBER HAS BEEN BUILT        *               
  * *********************************************
   600-RANDGEN-CLEANUP.
       ADD 1 TO COUNT-OF-ACCESSES.
       COMPUTE RANDOM-NUMBER = 
            RANDOM-NUMBER-BUILT - LOW-RANGE. 
  * *******************************************************
  * THE NEXT 3 LINE OF CODE ARE FOR TESTING  ON CONSOLE   *  
  * *******************************************************
       DISPLAY RANDOM-NUMBER.
       IF COUNT-OF-ACCESSES < RANDOM-NUMBERS-NEEDED
        GO TO 100-RANDGEN-EDIT-HOUSEKEEPING.     
   900-EXIT-RANDGEN.
       IF RANDOM-MSG NOT = SPACE
        DISPLAY 'RANDOM-MSG: ' RANDOM-MSG.
        MOVE ZERO TO COUNT-OF-ACCESSES RANDOM-NUMBERS-NEEDED RANDOM-NUMBER. 
        MOVE SPACE TO YOU-PROVIDE-SEED RUN-AGAIN.
       DISPLAY 'RUN AGAIN Y OR N '
         NO ADVANCING.
       ACCEPT RUN-AGAIN.
       IF (RUN-AGAIN = 'Y' OR 'y')
         GO TO 100-RANDGEN-EDIT-HOUSEKEEPING.
       ACCEPT PAUSE-FOR-A-SECOND.
       GOBACK.