Fix the DEFTRANSFORM of RANDOM for hairy integer types.
[sbcl.git] / tests / random.pure.lisp
1 ;;;; various RANDOM tests without side effects
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
8 ;;;; from CMU CL.
9 ;;;;
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
13
14 (in-package :cl-user)
15
16 ;;; Tests in this file that rely on properties of the distribution of
17 ;;; the random numbers are designed to be fast and have a very low
18 ;;; probability of false positives, generally of the order of (expt 10 -60).
19 ;;; These tests are not intended to assure the statistical qualities of the
20 ;;; pseudo random number generator but to help find bugs in its and RANDOM's
21 ;;; implementation.
22
23 ;; When the type of the argument of RANDOM is a set of integers, a
24 ;; DEFTRANSFORM triggered that simply generated (REM (RANDOM-CHUNK) NUM),
25 ;; which has two severe problems: The resulting distribution is very uneven
26 ;; for most arguments of RANDOM near the size of a random chunk and the
27 ;; RANDOM-CHUNK used was always 32 bits, even under 64 bit wordsize which
28 ;; yields even more disastrous distributions.
29 (with-test (:name (:random :integer :set-of-integers :distribution))
30   (let* ((high (floor (expt 2 33) 3))
31          (mid (floor high 2))
32          (fun (compile nil `(lambda (x)
33                               (random (if x ,high 10)))))
34          (n1 0)
35          (n 10000))
36     (dotimes (i n)
37       (when (>= (funcall fun t) mid)
38         (incf n1)))
39     ;; Half of the values of (RANDOM HIGH) should be >= MID, so we expect
40     ;; N1 to be binomially distributed such that this distribution can be
41     ;; approximated by a normal distribution with mean (/ N 2) and standard
42     ;; deviation (* (sqrt N) 1/2). The broken RANDOM we are testing here for
43     ;; yields (/ N 3) and (* (sqrt N) (sqrt 2/9)), respectively. We test if
44     ;; N1 is below the average of (/ N 3) and (/ N 2). With a value of N of
45     ;; 10000 this is more than 16 standard deviations away from the expected
46     ;; mean, which has a probability of occurring by chance of below
47     ;; (expt 10 -60).
48     (when (< n1 (* n 5/12))
49       (error "bad RANDOM distribution: expected ~d, got ~d" (/ n 2) n1))))
50
51 (with-test (:name (:random :integer :set-of-integers :chunk-size))
52   (let* ((high (expt 2 64))
53          (fun (compile nil `(lambda (x)
54                               (random (if x ,high 10)))))
55          (n 200)
56          (x 0))
57     (dotimes (i n)
58       (setf x (logior x (funcall fun t))))
59     ;; If RANDOM works correctly, x should be #b111...111 (64 ones)
60     ;; with a probability of 1 minus approximately (expt 2 -194).
61     (unless (= x (1- high))
62       (error "bad RANDOM distribution: ~16,16,'0r" x))))