;;; -*- mode: lisp -*-
;;; $Id: moments.poplisp,v 1.0 2002/05/08 17:37:00 dada Exp $
(declaim (optimize (speed 3) (debug 0) (safety 0) (space 0) (compilation-speed 0)))
(defun quicksort (vec lo hi) ;; modified from from Roger Corman's posting in cll
(declare (fixnum hi lo) (type (simple-array double-float) vec))
(if (> hi lo)
(let* ((mid (round (+ lo hi) 2))
(i lo)
(j (+ hi 1))
(p (aref vec mid)))
(declare (fixnum i j) (double-float p))
(rotatef (aref vec mid) (aref vec lo)) ;; swap mid element to first
(loop
(loop do (incf i)
until (or (> i hi) (> p (aref vec i))))
(loop do (decf j)
until (or (<= j lo) (> (aref vec j) p)))
(if (< j i) (return))
(rotatef (aref vec i)(aref vec j)))
(rotatef (aref vec lo) (aref vec j)) ;;put partition element in place
(quicksort vec lo (- j 1)) (quicksort vec i hi))) vec)
(defun do-moments (data n mean)
(declare (fixnum n) (double-float mean) (type (simple-array double-float) data))
(let ((average_deviation 0.0d0)
(standard_deviation 0.0d0)
(variance 0.0d0)
(skew 0.0d0)
(kurtosis 0.0d0)
(median 0.0d0))
(declare (double-float mean average_deviation standard_deviation
variance skew kurtosis median))
(declare (inline quicksort))
(loop for i fixnum from 0 below n do
(let* ((deviation (- (the double-float (aref data i)) mean))
(deviation2 (* deviation deviation))
(deviation3 (* deviation deviation2))
(deviation4 (* deviation deviation3)))
(incf average_deviation (abs deviation))
(incf variance deviation2)
(incf skew deviation3)
(incf kurtosis deviation4)))
(setq average_deviation (/ average_deviation n))
(setq variance (/ variance (1- n)))
(setq standard_deviation (sqrt variance))
(cond ((> variance 0.0d0)
(setq skew (/ skew (* n variance standard_deviation)))
(setq kurtosis (- (/ kurtosis (* (coerce n 'double-float)
variance variance))
3.0d0))))
(setf data (quicksort data 0 (1- n)))
(let ((mid (/ n 2)))
(fixnum mid)
(if (zerop (mod n 2))
(setq median (/ (+ (the double-float (aref data mid))
(the double-float (aref data (1- mid))))
2.0d0))
(setq median (aref data mid))))
(format t "n: ~A~%" n)
(format t "median: ~,6K~%" median)
(format t "mean: ~,6K~%" mean)
(format t "average_deviation: ~,6K~%" average_deviation)
(format t "standard_deviation: ~,6K~%" standard_deviation)
(format t "variance: ~,6K~%" variance)
(format t "skew: ~,6K~%" skew)
(format t "kurtosis: ~,6K~%" kurtosis)))
(let ((buffer (make-string 4096))
(start 0)
(end 0)
(result 0.0d0)
(char #\X)
(stream *standard-input*)
(eof-p nil))
(declare (fixnum start end) (double-float result))
(labels ((get-char ()
(when (= start end)
(setf start 0)
(setf end (read-sequence buffer stream))
(when (zerop end)
(setf eof-p t)
(setf char #\Z) ;any non-digit will do
(return-from get-char nil)))
(setf char (schar buffer start))
(incf start))
(get-dfloat ();; parse double float hack someone should rewrite this
(let ((minusp nil)
(expminusp nil)
(before-dp 0)
(after-dp 0)
(dec-digits 0)
(exponent 0))
(declare (fixnum before-dp after-dp exponent dec-digits)
(inline digit-char-p char=))
(loop while (and
(not
(or (and (char= #\- char)
(setq minusp t))
(digit-char-p char 10)))
(get-char)))
(loop
do (let ((weight (digit-char-p char 10)))
(declare (type (or null fixnum) weight))
(if weight
(setq before-dp (+ weight (the fixnum (* before-dp 10))))
(return)))
until (not (get-char)))
(if minusp (setf before-dp (- before-dp)))
(when (char= #\. char)
(loop while (get-char)
do (let ((weight (digit-char-p char 10)))
(declare (type (or null (signed-byte 32)) weight))
(if weight
(setq after-dp (+ weight (the fixnum (* after-dp 10)))
dec-digits (the fixnum (1+ dec-digits)))
(return)))))
(when (or (char= #\e char) (char= #\E char))
(get-char)
(when (char= #\- char)
(setq expminusp t)
(get-char))
(loop
do (let ((weight (digit-char-p char 10)))
(declare (type (or null fixnum) weight))
(if weight
(setq exponent (+ weight (the fixnum (* exponent 10))))
(return)))
until (not (get-char)))
(if expminusp (setf exponent (- exponent))))
(setq result
(float (*
(+ (float before-dp 1.0d0)
(if (zerop after-dp) 0.0d0
(* (float after-dp 1.0d0)
(if (zerop dec-digits) 1.0d0
(expt 10.0d0 (float (- dec-digits) 1.0d0))))))
(if (zerop exponent) 1.0d0
(expt 10.0d0 (float exponent 1.0d0)))) 1.0d0)))))
(let ((sum 0.0d0)
nums )
(declare (double-float sum) (inline vector-push-extend))
(let* ((array-size 10000)
(numbuffer (make-array array-size :element-type 'double-float))
(buflist (list numbuffer)) ;; Doug's idea put these together later
(fill-pointer 0))
(loop
(get-dfloat)
(if (not eof-p)
(progn
(incf sum result)
(setf (aref numbuffer fill-pointer) result)
(incf fill-pointer)
(when (= fill-pointer array-size)
(push
(setf numbuffer (make-array array-size :element-type 'double-float))
buflist)
(setf fill-pointer 0)))
(return)))
(let* ((num-arrays (length buflist))
(num-elem (+ (* (1- num-arrays) array-size) fill-pointer)))
(setf nums (make-array num-elem :element-type 'double-float))
(locally (declare (type (simple-array double-float) nums))
(loop for i fixnum from 0 to (1- num-arrays) do
(setf (subseq nums (* i array-size))
(the (simple-array double-float)
(elt buflist (- (1- num-arrays) i))))) ;;buflist is rev'd
(do-moments nums num-elem (/ sum num-elem))))))))