;;; -*- 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))))))))