with-gensyms
[alexandria.git] / numbers.lisp
blob8b5ca1e5d163199dee84d61d48d26df6ee08b29d
1 (in-package :alexandria)
3 (declaim (inline clamp))
4 (defun clamp (number min max)
5 "Clamps the NUMBER into [MIN, MAX] range. Returns MIN if NUMBER lesser then
6 MIN and MAX if NUMBER is greater then MAX, otherwise returns NUMBER."
7 (if (< number min)
8 min
9 (if (> number max)
10 max
11 number)))
13 (defun gaussian-random (&optional min max)
14 "Returns two gaussian random double floats as the primary and secondary value,
15 optionally constrained by MIN and MAX. Gaussian random numbers form a standard
16 normal distribution around 0.0d0."
17 (labels ((gauss ()
18 (loop
19 for x1 = (- (random 2.0d0) 1.0d0)
20 for x2 = (- (random 2.0d0) 1.0d0)
21 for w = (+ (expt x1 2) (expt x2 2))
22 when (< w 1.0d0)
23 do (let ((v (sqrt (/ (* -2.0d0 (log w)) w))))
24 (return (values (* x1 v) (* x2 v))))))
25 (guard (x min max)
26 (unless (<= min x max)
27 (tagbody
28 :retry
29 (multiple-value-bind (x1 x2) (gauss)
30 (when (<= min x1 max)
31 (setf x x1)
32 (go :done))
33 (when (<= min x2 max)
34 (setf x x2)
35 (go :done))
36 (go :retry))
37 :done))
38 x))
39 (multiple-value-bind (g1 g2) (gauss)
40 (values (guard g1 (or min g1) (or max g1))
41 (guard g2 (or min g2) (or max g2))))))
43 (declaim (inline iota))
44 (defun iota (n &key (start 0) (step 1))
45 "Return a list of n numbers, starting from START (with numeric contagion
46 from STEP applied), each consequtive number being the sum of the previous one
47 and STEP. START defaults to 0 and STEP to 0.
49 Examples:
51 (iota 4) => (0 1 2 3 4)
52 (iota 3 :start 1 :step 1.0) => (1.0 2.0 3.0)
53 (iota 3 :start -1 :step -1/2) => (-1 -3/2 -2)
55 (declare (type (integer 0) n) (number start step))
56 (loop repeat n
57 ;; KLUDGE: get numeric contagion right for the first element too
58 for i = (+ start (- step step)) then (+ i step)
59 collect i))
61 (declaim (inline lerp))
62 (defun lerp (v a b)
63 "Returns the result of linear interpolation between A and B, using the
64 interpolation coefficient V."
65 (+ a (* v (- b a))))
67 (declaim (inline mean))
68 (defun mean (sample)
69 "Returns the mean of SAMPLE. SAMPLE must be a sequence of numbers."
70 (/ (reduce #'+ sample) (length sample)))
72 (declaim (inline median))
73 (defun median (sample)
74 "Returns median of SAMPLE. SAMPLE must be a sequence of real numbers."
75 (let* ((vector (sort (copy-sequence 'vector sample) #'<))
76 (length (length vector))
77 (middle (truncate length 2)))
78 (if (oddp length)
79 (aref vector middle)
80 (/ (+ (aref vector middle) (aref vector (1+ middle))) 2))))
82 (declaim (inline variance))
83 (defun variance (sample &key (biased t))
84 "Variance of SAMPLE. Returns the biased variance if BIASED is true (the default),
85 and the unbiased estimator of variance if BIASED is false. SAMPLE must be a
86 sequence of numbers."
87 (let ((mean (mean sample)))
88 (/ (reduce (lambda (a b)
89 (+ a (expt (- b mean) 2)))
90 sample
91 :initial-value 0)
92 (- (length sample) (if biased 0 1)))))
94 (declaim (inline standard-deviation))
95 (defun standard-deviation (sample &key (biased t))
96 "Standard deviation of SAMPLE. Returns the biased standard deviation if
97 BIASED is true (the default), and the square root of the unbiased estimator
98 for variance if BIASED is false (which is not the same as the unbiased
99 estimator for standard deviation). SAMPLE must be a sequence of numbers."
100 (sqrt (variance sample :biased biased)))
102 (define-modify-macro maxf (&rest numbers) max
103 "Modify-macro for MAX. Sets place designated by the first argument to the
104 maximum of its original value and NUMBERS.")
106 (define-modify-macro minf (&rest numbers) min
107 "Modify-macro for MIN. Sets place designated by the first argument to the
108 minimum of its original value and NUMBERS.")