代码之家  ›  专栏  ›  技术社区  ›  myselfesteem

Lisp有偏数发生器

  •  2
  • myselfesteem  · 技术社区  · 11 年前

    是否有一种方法可以在lisp中指定随机生成器中的偏差?

    例如,如果我有一系列数字。我如何指定范围前半部分的数字比后半部分的数字有3倍的可能性?

    2 回复  |  直到 11 年前
        1
  •  3
  •   Community Mohan Dere    9 年前

    我喜欢 Barmar's answer ,并且它很好地处理任意权重。但是,它确实需要两次调用 随机的 ,这可能是不可取的。另一种方法是创建一个向量,其中包含根据其预期频率出现的元素。E、 例如,如果元素a和b的选择概率为1/3和2/3,那么可以创建一个数组 (a b b) 并从中随机选择。

    (defun biased-generator (values weights)
      (multiple-value-bind (total values)
          (loop for v in values
             for w in weights
             nconc (make-list w :initial-element v) into vs
             sum w into total
             finally (return (values total (coerce vs 'vector))))
        (lambda ()
          (aref values (random total)))))
    

    CL-USER> (defparameter *gen* (biased-generator '(a b) '(1 2)))
    *GEN*
    CL-USER> (loop for i from 1 to 100 collect (funcall *gen*))
    (A A B A B A A B B A B B A A A B A A B A A A B A A A B B B B B A B B B B A A B
     A B B A A A A B B B A A A A B A A B B B A A B B B A B B B B B B B B B B A B A
     A A A B B B B A B A A B B A B A A B B B B B)
    CL-USER> (let ((abs (loop for i from 1 to 10000 collect (funcall *gen*))))
               (list (count 'a abs)
                     (count 'b abs)))
    (3293 6707)
    
        2
  •  2
  •   Barmar    11 年前

    分两步进行:

    首先,在任意范围内选择一个随机数,并确定它是否在该范围的前3/4。如果是,则在给定范围的前半部分选择一个随机数,否则在后半部分选择随机数:

    (defun biased_random(low high) {
        (let ((temp (random 1.0))
              (middle (floor (+ high low) 2)))
          (if (< temp 0.75)
              (+ low (random (- middle low)))
              (+ middle (random (- high middle)))))
    
    推荐文章