1# ==== Purpose ==== 2# 3# Generate a random number in such a way that the sequence of numbers 4# generated by successive calls can be deterministic. 5# 6# ==== Usage ==== 7# 8# --let $rand_type= { int | float | decide | init } 9# [--let $rand_min= MIN_VALUE] 10# [--let $rand_max= MAX_VALUE] 11# [--let $rand_probability= THRESHOLD] 12# [--let $rand_seed= SEED] 13# --source include/rand.inc 14# --echo Random number: $rand 15# 16# Parameters: 17# 18# $rand_type 19# If set to 'int', generates an integer in the range 20# [$rand_min, $rand_max). 21# 22# If set to 'float', generates a floating point number in the 23# range [$rand_min, $rand_max). 24# 25# If set to 'decide', generates 1 with probability 26# $rand_probability and 0 with probability 1-$rand_probability. 27# 28# If set to 'init', does not generate $rand, but initializes 29# the $rand_seed in case this is the first invocation. 30# 31# $rand_min, $rand_max 32# Range of values for $rand_type=int or $rand_type=float. 33# These are evaluated in an SQL query, so may contain valid 34# arithmetic operations. 35# 36# $rand_probability 37# Probability to get a '1' if $rand_type=decide. 38# This is evaluated in an SQL query, so may contain valid 39# arithmetic operations. 40# 41# $rand_seed 42# The seed value. If you want to set the seed to a random number 43# that is different for each invokation of the test, set 44# $rand_seed to the empty string. Normally, $rand_seed is only 45# read in the first invokation of rand.inc. If you want to reset 46# the seed later, set $_rand_state to the empty string. 47# 48# ==== Implementation ==== 49# 50# This RNG uses the following multiply-with-carry algorithm: 51# int32 z, w; 52# if (z == 0) z = 1; 53# if (w == 0) w = 1; 54# z = 36969 * (z & 65535) + (z >> 16); 55# w = 18000 * (w & 65535) + (w >> 16); 56# rand = (z << 16) + w; 57# In this implementation, z is stored in the low 32 bits and w in the 58# high 32 bits of $_rand_state. 59 60--let $_maxint32= ((1 << 32) - 1) 61 62if ($_rand_state == '') 63{ 64 if ($rand_seed == '') 65 { 66 --let $rand_seed= `SELECT FLOOR(RAND() * (1 << 63))` 67 } 68 --let $write_var= $rand_seed 69 --let $write_to_file= $MYSQLTEST_VARDIR/tmp/rand_seed 70 --source include/write_var_to_file.inc 71 --let $_rand_state= $rand_seed 72 --let $_rand_lo= IF(($_rand_state) & $_maxint32 = 0, 1, ($_rand_state) & $_maxint32) 73 --let $_rand_hi= IF(($_rand_state) >> 32 = 0, 1, ($_rand_state) >> 32) 74 --let $_rand_state= `SELECT ((36969 * $_rand_lo + ($_rand_lo >> 16)) & $_maxint32) + (((18000 * ($_rand_hi & 65535) + ($_rand_hi >> 16)) & $_maxint32) << 32)` 75} 76 77--let $_rand_lo= IF(($_rand_state) & $_maxint32 = 0, 1, ($_rand_state) & $_maxint32) 78--let $_rand_hi= IF(($_rand_state) >> 32 = 0, 1, ($_rand_state) >> 32) 79--let $_rand_state= `SELECT ((36969 * $_rand_lo + ($_rand_lo >> 16)) & $_maxint32) + (((18000 * ($_rand_hi & 65535) + ($_rand_hi >> 16)) & $_maxint32) << 32)` 80--let $rand= ((($_rand_state << 16) + ($_rand_state >> 32)) & $_maxint32) 81 82if ($rand_type == decide) 83{ 84 --let $_rand_probability= 0.5 85 if ($rand_probability != '') 86 { 87 --let $_rand_probability= $rand_probability 88 } 89 --let $rand= `SELECT IF($rand / (1 << 32) < ($rand_probability), 1, 0)` 90} 91if ($rand_type != decide) 92{ 93 --let $_rand_min= 0 94 if ($rand_min) 95 { 96 --let $_rand_min= $rand_min 97 } 98 --let $_rand_max= 1 99 if ($rand_max) 100 { 101 --let $_rand_max= $rand_max 102 } 103 if ($rand_type == int) 104 { 105 --let $rand= `SELECT ($_rand_min) + ($rand % (($_rand_max) - ($_rand_min)))` 106 } 107 if ($rand_type == float) 108 { 109 --let $rand= `SELECT ($_rand_min) + ($rand * (($_rand_max) - ($_rand_min)) / (1 << 32))` 110 } 111} 112--error 0,1 113--remove_file $MYSQLTEST_VARDIR/tmp/rand_seed 114