我正在尝试创建一个随机数生成器(稍后将一些随机数转换为[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
如果您有解决原始问题的建议(创建一个由字母数字字符组成的随机密码),我也很高兴听到它。
编辑: 通过省略种子,两个问题立即得到解决。更多背后的结论可以在下面的评论中找到。如果有人解释为什么不同的种子仍会产生相同的价值,我会很高兴听到它!
答案 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.