ABAP Quick - Random numbers
How do you create a neatly working random number generator in ABAP? We show you in this little article and what you should pay attention to.
Table of contents
A random number generator in SAP seems rather lost, why should you need something like that, when everything is designed for logic? The answer is more for fun or for a test application based on random databases. The implementation is very simple, but you should pay attention to a few points to get a true random number generator.
Class cl_abap_random
The foundation is the class cl_abap_random, which can generate random numbers. To do this, create a simple instance using the factory method. With the different methods you can then generate different random numbers. In the example we have a simple cube that produces the numbers from 1 to 6.
" Create instance with factory
DATA(lo_rand) = cl_abap_random=>create( ).
" Random number from 1 till 6 (integer)
DATA(ld_num) = lo_rand->intinrange( low = 1 high = 6 ).
Less Random
Problem in the generation of random numbers is the chance itself. Because the generated numbers are not really very random in the order. For this we have the following experimental setup:
DO 15 TIMES.
DATA(lo_rand) = cl_abap_random=>create( ).
DO 30 TIMES.
WRITE: CONV char1( lo_rand->intinrange( low = 1 high = 6 ) ).
ENDDO.
NEW-LINE.
ENDDO.
For each generated output line, the random number generator is instantiated again. The result is, however, that each row looks the same, the generated random numbers are repeated exactly in their order. However, this does not correspond to any coincidence, since the same result would be generated with each test case.
Solution
For this we need a little help to generate really random number series and that with each pass. The class's factory method picks up another parameter, the seed. This seed sets the starting value of the random generator. Working with a fixed start value/seed also produces the same result and is not recommended.
Therefore, at the beginning we need a "seed generator" that provides us random seeds for the random number generator. This should then also have been generated on a relatively random number. In our example, we use month/day, as well as the current time, to get the starting value. With this start value, we then generate a seed generator.
" Create first seed
TRY.
" Seed with date and time
DATA(ld_seed) = CONV i( |{ sy-datum(4) }{ sy-uzeit }| ).
CATCH cx_sy_conversion_overflow.
" Fallback seed number
ld_seed = 1337.
ENDTRY.
" Seed generator
mo_seed = cl_abap_random=>create( ld_seed ).
The instance of this generator should be kept static or global so that it does not have to be recreated each time.
With the help of our seed generator, we can now create a class of cl_abap_random each time and provide it with a random seed number to really get even random numbers.
" Create instance
DATA(lo_rand) = cl_abap_random=>create( mo_seed->intinrange( low = 1 high = 999999 ) ).
Here's the complete example for creating the new cube result. Again 15 rows of numbers are created and each time a new instance of the random number generator is generated, this time only with the help of our seed generator.
" Create seed number
TRY.
DATA(ld_seed) = CONV i( |{ sy-datum(4) }{ sy-uzeit }| ).
CATCH cx_sy_conversion_overflow.
ld_seed = 1337.
ENDTRY.
DATA(lo_seed) = cl_abap_random=>create( ld_seed ).
" Process logic
DO 15 TIMES.
DATA(lo_rand) = cl_abap_random=>create( lo_seed->intinrange( low = 1 high = 999999 ) ).
DO 30 TIMES.
WRITE: CONV char1( lo_rand->intinrange( low = 1 high = 6 ) ).
ENDDO.
NEW-LINE.
ENDDO.
The current result is impressive and looks more like a coincidence than before. Here are 3 examples of what the program has generated in numbers and you will find that these are reasonably good looking numbers.
Full example
Here you can find the complete class for generating random numbers. According to the logic above, the creation of the seed in the class constructor and the constructor initialize the random generator.
CLASS zcl_bs_demo_random DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS class_constructor.
METHODS constructor
IMPORTING id_min TYPE i DEFAULT 1
id_max TYPE i DEFAULT 6.
METHODS rand
RETURNING VALUE(rd_rand) TYPE i.
PRIVATE SECTION.
CLASS-DATA mo_seed TYPE REF TO cl_abap_random.
DATA mo_rand TYPE REF TO cl_abap_random.
DATA md_from TYPE i.
DATA md_to TYPE i.
ENDCLASS.
CLASS zcl_bs_demo_random IMPLEMENTATION.
METHOD class_constructor.
TRY.
DATA(ld_date) = cl_abap_context_info=>get_system_date( ).
DATA(ld_time) = cl_abap_context_info=>get_system_time( ).
DATA(ld_seed) = CONV i( |{ ld_date+4 }{ ld_time }| ).
CATCH cx_sy_conversion_overflow.
ld_seed = 1337.
ENDTRY.
mo_seed = cl_abap_random=>create( ld_seed ).
ENDMETHOD.
METHOD constructor.
md_from = id_min.
md_to = id_max.
mo_rand = cl_abap_random=>create( mo_seed->intinrange( low = 1
high = 10000 ) ).
ENDMETHOD.
METHOD rand.
rd_rand = mo_rand->intinrange( low = md_from
high = md_to ).
ENDMETHOD.
ENDCLASS.
Conclusion
The implementation of a random number generator should not be a problem for you now, if you pay attention to the subtleties in the implementation. With the help of our example, it should no longer be a problem for you to implement an efficient solution.