0

I've got this:

(let ((num 1))
  (mapcar (lambda (x)
            (cons x (if (evenp (setf num (random 299)))
                        (1+ num)
                        (num))))
          '(a b c d e f)))

which should produce something like this:

 ((A . 37) (B . 283) (C . 232) (D . 251) (E . 273) (F . 170) 

only with odd numbers. Yes, very kludgy looking. Is there something with random-state that would help? Or the "hidden system variable" that holds onto that initial random calculation? Here's a global function I tried:

(defun random-odd ()
  (let ((num 0))
    (if (evenp (setf num (random 299)))
        (1+ num)
      (num))))

Also not working. What am I missing here?

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
147pm
  • 2,137
  • 18
  • 28

2 Answers2

5

Your random-odd is almost fine except for the style and using num in the function position (remember, Lisp parentheses are meaningful):

(defun random-odd ()
  (let ((num (random 299)))
    (if (evenp num)
        (1+ num)
        num)))

The subtle problem with this function is that the probability of getting 299 is half the probability of getting any other odd number from 1 to 297.

This is because (random 299) returns numbers from 0 to 298 inclusive with equal probability 1/299. Thus random-odd will return, say, 17 with probability 2/299 (if random returns 17 or 16) but it will return 299 with probability 1/299 (if random returns 298).

Thus I would suggest

(defun random-odd (even-limit)
  "Return an odd random number from 0 to EVEN-LIMIT, exclusive."
  (assert (evenp even-limit) (even-limit)
          "~S: ~S must be even" 'random-odd 'even-limit)
  (let ((num (random even-limit)))
    (if (evenp num)
        (1+ num)
        num)))

A completely equivalent approach would be

(defun random-odd (half-limit)
  "Return a random odd number from 1 to half-limit*2-1 inclusive."
  (1+ (ash (random half-limit) 1)))
sds
  • 58,617
  • 29
  • 161
  • 278
  • Wouldn't it make more sense to (1+ (* 2 (random 150)))? My statistics knowledge is a bit weak though. – BRPocock Nov 28 '17 at 01:51
  • To clarify, seems like ×2+1 avoids a lot of unnecessary computation without sacrificing much, if any, clarity, but I'm uncertain if it would subtly seem the results somehow. – BRPocock Nov 28 '17 at 01:54
  • The outcome, but unless someone has better optimizers than I expect, I'd think the compare and branch-or-increment would add some overhead. Probably trivial compared to the cons, but /shrug. – BRPocock Nov 28 '17 at 04:20
  • @BRFennPocock but you have to compute half-limit instead of the actual limit ;-) – sds Nov 28 '17 at 04:33
  • 1
    sure, but every optimizer can do a ÷2 = Ash -1, and that's outside the loop. I know, I deal in tighter margins than most people care to, but /shrug … Define-Compiler-Macro is always there, I guess. – BRPocock Nov 28 '17 at 04:34
1
(mapcar #'(lambda (x)
    (let ((num (random 299)))
      (cons x (if (evenp num)
          (1+ num)
        num))))
'(a b c d e f))
karsten
  • 11
  • 1
  • Thanks karsten, this is what I went with, embedding it in a `flet`. Forgot you could put a `let` inside a `mapcar`. – 147pm Nov 28 '17 at 18:40