From d8b78e823e06d7e731fdc3c82af89231673d429d Mon Sep 17 00:00:00 2001 From: Benjamin Greenman Date: Mon, 6 Mar 2017 18:43:04 -0500 Subject: [PATCH] relax contract for (random min max [rand-gen]) (#1626) Relax contract for `(random min max [rand-gen])` to accept any pair of integers such that: - `(< min max)` - `(- max min)` is between 1 and 4294967087 --- .../scribblings/reference/numbers.scrbl | 4 +- .../racket-test-core/tests/racket/number.rktl | 14 +++- racket/collects/racket/private/pre-base.rkt | 68 ++++++++++++------- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/pkgs/racket-doc/scribblings/reference/numbers.scrbl b/pkgs/racket-doc/scribblings/reference/numbers.scrbl index f80e6b2f1e..4a06ccee48 100644 --- a/pkgs/racket-doc/scribblings/reference/numbers.scrbl +++ b/pkgs/racket-doc/scribblings/reference/numbers.scrbl @@ -842,8 +842,8 @@ both in binary and as integers. [rand-gen pseudo-random-generator? (current-pseudo-random-generator)]) exact-nonnegative-integer?] - [(random [min (integer-in 1 4294967087)] - [max (integer-in 1 4294967087)] + [(random [min exact-integer?] + [max (integer-in (+ 1 min) (+ 4294967087 min))] [rand-gen pseudo-random-generator? (current-pseudo-random-generator)]) exact-nonnegative-integer?] diff --git a/pkgs/racket-test-core/tests/racket/number.rktl b/pkgs/racket-test-core/tests/racket/number.rktl index 7e814768be..64083fdd5b 100644 --- a/pkgs/racket-test-core/tests/racket/number.rktl +++ b/pkgs/racket-test-core/tests/racket/number.rktl @@ -2462,9 +2462,15 @@ (test (begin (random-seed 23) (list (random 10) (random 20) (random 30))) 'random-seed-same (begin (random-seed 23) (list (random 10) (random 20) (random 30)))) -(test (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40))) +(test (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40) + (random 0 5) (random -10 10) (random -9 -3) + (random big-num (+ 10 big-num)) + (random (- -3 big-num) (- big-num)))) 'random-seed-same2 - (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40)))) + (begin (random-seed 23) (list (random 10 20) (random 20 30) (random 30 40) + (random 0 5) (random -10 10) (random -9 -3) + (random big-num (+ 10 big-num)) + (random (- -3 big-num) (- big-num))))) (test (begin (random-seed 23) (list (random-ref '(1 2 3)) (random-ref '(4 5 6)) (random-ref '(7 8 9)))) 'random-seed-same3 (begin (random-seed 23) (list (random-ref '#(1 2 3)) (random-ref '#(4 5 6)) (random-ref '#(7 8 9))))) @@ -2484,7 +2490,11 @@ (err/rt-test (random 4294967088)) (err/rt-test (random (expt 2 32))) (err/rt-test (random big-num)) +(err/rt-test (random big-num)) (err/rt-test (random 10 5)) +(err/rt-test (random -2 -3)) +(err/rt-test (random 0 big-num)) +(err/rt-test (random -big-num 0)) (random-seed 101) (define x (list (random 10) (random 20) (random 30))) diff --git a/racket/collects/racket/private/pre-base.rkt b/racket/collects/racket/private/pre-base.rkt index a4892d9180..2459ef4d9d 100644 --- a/racket/collects/racket/private/pre-base.rkt +++ b/racket/collects/racket/private/pre-base.rkt @@ -98,18 +98,6 @@ (define-values (double-flonum?) ; for symmetry with single-flonum? (lambda (x) (flonum? x))) - (define-values (enforce-random-int-range) - (lambda (x) - (unless (and (exact-positive-integer? x) - (<= x 4294967087)) - (raise-argument-error 'random "(integer-in 1 4294967087)" x)))) - (define-values (enforce-greater) - (lambda (x y) - (unless (> y x) - (raise-argument-error - 'random - (string-append "integer greater than " (number->string x)) - y)))) (begin-encourage-inline (define-values (-random) ; more featureful than #%kernel's `random` (let ([random ; to get the right name @@ -121,26 +109,54 @@ (random x)] [(x y) ;; two args, either max and prng, or min and max - (cond [(exact-positive-integer? y) ; min and max case - (enforce-random-int-range x) - (enforce-random-int-range y) - (enforce-greater x y) - (+ x (random (- y x)))] + (cond [(exact-integer? y) ; min and max case + (unless (exact-integer? x) + (raise-argument-error 'random "exact-integer?" 0 x y)) + (unless (< x y) + (raise-argument-error + 'random + (string-append "(>/c " (number->string x) ")") + 1 x y)) + (let ([d (- y x)]) + (unless (<= d 4294967087) + (raise-arguments-error + 'random + "difference between arguments is greater than 4294967087" + "min" x "max" y)) + (+ x (random d)))] [(pseudo-random-generator? y) ; int and prng case - (enforce-random-int-range x) + (unless (and (exact-integer? x) + (<= 1 x 4294967087)) + (raise-argument-error + 'random "(integer-in 1 4294967087)" 0 x y)) (random x y)] [else + (unless (exact-integer? x) + (raise-argument-error 'random "exact-integer?" 0 x y)) (raise-argument-error 'random - "(or/c (integer-in 1 4294967087) pseudo-random-generator?)" - y)])] + "(or/c exact-integer? pseudo-random-generator?)" + 1 x y)])] [(min max prng) ; three args: min, max, and prng - (enforce-random-int-range min) - (enforce-random-int-range max) - (enforce-greater min max) - (unless (pseudo-random-generator? prng) - (raise-argument-error 'random "pseudo-random-generator?" prng)) - (+ min (random (- max min) prng))])]) + (unless (exact-integer? min) + (raise-argument-error 'random "exact-integer?" 0 min max prng)) + (unless (exact-integer? max) + (raise-argument-error 'random "exact-integer?" 1 min max prng)) + (unless (< min max) + (raise-argument-error + 'random + (string-append "(>/c " (number->string min) ")") + 1 min max prng)) + (let ([d (- max min)]) + (unless (<= d 4294967087) + (raise-arguments-error + 'random + "difference between first and second arguments is greater than 4294967087" + "min" min "max" max "rand-gen" prng)) + (unless (pseudo-random-generator? prng) + (raise-argument-error + 'random "pseudo-random-generator?" 2 min max prng)) + (+ min (random d prng)))])]) random))) (define-values (new:collection-path)