xyzzy電卓半端移植その2
si接頭辞が使えるようにしてみた。何やってるの感強い。
例えば秒でいえばsだけ定義してあるとmsとかnsとかが定義されているかのようにふるまう。マイクロ秒はus*1。シンボルの頭1文字を抜かしたところが定義済みなら適当に10のうん乗倍するということをしている。
- 7.2km角は何立方cmか
$ (7.2 km)^3 / cm^3 3.73248E17
- 1gの質量エネルギーはテラジュール換算でいくらか
$ 1.0 g * c^2 / TJ 89.875517873681764
- 1GeVは何g相当か
$ 1GeV/(g c^2) 1.782661728026788d-24
という感じ。有効数字とかは扱ってない。電卓だし。
ちなみに重力定数はg_に変わった。
前回書き忘れたけどbyeとかquitと打つと終了。Ctrl+Dでもよい。
あと単位定義と定数定義を微妙に別のマクロにした。
calc.l
; 変更なし
units.l
(in-package :calc) (defvar *fundamental-units* '(|kg| |m| |s| |C| |K|)) ;; (defvar *si-prefix-alist* `((|y| . ,(expt 10 -24)) (|z| . ,(expt 10 -21)) (|a| . ,(expt 10 -18)) (|f| . ,(expt 10 -15)) (|p| . ,(expt 10 -12)) (|n| . ,(expt 10 -9)) (|u| . ,(expt 10 -6)) (|m| . ,(expt 10 -3)) (|c| . ,(expt 10 -2)) (|d| . ,(expt 10 -1)) (|K| . ,(expt 10 3)) (|k| . ,(expt 10 3)) (|h| . ,(expt 10 2)) (|M| . ,(expt 10 6)) (|G| . ,(expt 10 9)) (|T| . ,(expt 10 12)) (|P| . ,(expt 10 15)) (|Z| . ,(expt 10 18)) (|Y| . ,(expt 10 21)))) ;da とか使わないよね? (defun zero-dimension-list () (make-list (length *fundamental-units*) :initial-element 0)) (defstruct (unit (:constructor make-unit)) ; name (value 1) (dimensions (zero-dimension-list))) (defun dimension (fundamental-unit u) (nth (position fundamental-unit *fundamental-units*) (unit-dimensions u))) (dolist (u *fundamental-units*) (setf (symbol-value u) ; (make-unit :name (symbol-name u)) (make-unit) ) (setf (nth (position u *fundamental-units*) (unit-dimensions (symbol-value u))) 1)) (defun multiply-unit (&rest args) (let ((units (remove-if-not #'unit-p args)) (numbers (remove-if #'unit-p args))) (if (null units) (apply #'* numbers) (make-unit :value (* (apply #'* numbers) (apply #'* (mapcar #'unit-value units))) :dimensions (apply #'mapcar #'+ (mapcar #'unit-dimensions units)))))) (defun invert-unit (arg) (if (unit-p arg) (make-unit :value (/ (unit-value arg)) :dimensions (mapcar #'- (unit-dimensions arg))) (/ arg))) (defun divide-unit (unit1 &rest units) (if (null units) (invert-unit unit1) (apply #'multiply-unit unit1 (mapcar #'invert-unit units)))) (defun add-unit (&rest args) (if (numberp (car args)) (apply #'+ args) (if (null (cdr args)) (car args) (if (equal (unit-dimensions (car args)) (unit-dimensions (cadr args))) (let ((next (apply #'add-unit (cdr args)))) (make-unit :value (+ (unit-value (car args)) (unit-value next)) :dimensions (unit-dimensions (car args)))) (error "dimension does't match"))))) (defun subtract-unit (&rest args) (if (numberp (car args)) (apply #'- args) (if (null (cdr args)) (multiply-unit -1 (car args)) (if (equal (unit-dimensions (car args)) (unit-dimensions (cadr args))) (let ((rest (apply #'add-unit (cdr args)))) (make-unit :value (- (unit-value (car args)) (unit-value rest)) :dimensions (unit-dimensions (car args)))) (error "dimension doesn't match"))))) (defun 1+-unit (arg) (add-unit arg 1)) (defun 1--unit (arg) (subtract-unit arg 1)) (defun expt-unit (base power) (if (unit-p base) (make-unit :value (expt (unit-value base) power) :dimensions (mapcar #'(lambda (dim) (* dim power)) (unit-dimensions base))) (expt base power))) (defun sqrt-unit (base) (expt-unit base 1/2)) (defun si-unit-to-unit (s) (if (not (or (numberp s) (unit-p s))) (if (> (length (symbol-name s)) 1) (let ((prefix (intern (subseq (symbol-name s) 0 1) :calc)) (unit (intern (subseq (symbol-name s) 1) :calc))) (if (and (not (boundp s)) (boundp unit) (assoc prefix *si-prefix-alist*)) (multiply-unit (cdr (assoc prefix *si-prefix-alist*)) (eval unit)) s)) s) s)) (defun print-unit (arg) (if (unit-p arg) (progn (princ (unit-value arg)) (dolist (u *fundamental-units*) (let ((deg (nth (position u *fundamental-units*) (unit-dimensions arg)))) (unless (zerop deg) (if (= 1 deg) (format t " ~A" (symbol-name u)) (format t " ~A^~D" (symbol-name u) deg)))))) (princ arg))) (defun with-unit-calculation% (tree) (if tree (if (listp tree) (cons (with-unit-calculation% (car tree)) (with-unit-calculation% (cdr tree))) (cond ((eq tree '+) 'add-unit) ((eq tree '-) 'subtract-unit) ((eq tree '*) 'multiply-unit) ((eq tree '/) 'divide-unit) ((eq tree 'expt) 'expt-unit) ((eq tree '|expt|) 'expt-unit) ((eq tree 'sqrt) 'sqrt-unit) ((eq tree '|sqrt|) 'sqrt-unit) ((eq tree '1+) '1+-unit) ((eq tree '1-) '1--unit) ; (t tree))))) (t (si-unit-to-unit tree)))))) (defmacro with-unit-calculation (sexp) `(eval (with-unit-calculation% ',sexp))) (defmacro define-unit (name definition) `(defvar ,name (with-unit-calculation ,definition))) (defmacro define-const (name value &optional (unit 1)) `(defvar ,name (with-unit-calculation (* ,value ,unit)))) ;;;; ;; mathematical constants (define-const |pi| pi) (define-const |Pi| pi) (define-const |E| (exp 1.0d0)) ; combined units and constants ;; aux. (define-unit |mol| 1) (define-unit |sec| 1) (define-unit |meter| 1) (define-unit |rad| 1) (define-unit |deg| (/ pi 180)) ;; combined units (define-unit |N| (* |kg| (/ |m| |s| |s|))) (define-unit |J| (* N |m|)) (define-unit |A| (/ C |s|)) (define-unit |V| (/ J C)) (define-unit |H| (* V (/ A) |s|)) (define-unit |F| (/ C V)) (define-unit |Ohm| (/ V A)) (define-unit |W| (* J |s|)) (define-unit |Weber| (* N |m| (/ A))) (define-unit |Tesla| (/ |Weber| |m| |m|)) (define-unit |Pa| (/ N |m| |m|)) ;; scientific constants in MKSA (define-const |e| 1.60217646d-19 C) (define-const |c| 299792458 (/ |m| |s|)) (define-const |h| 6.626068d-34 (* J |s|)) (define-const |hbar| (* |h| (* 2 pi))) (define-const |G| 6.67300d-11 (* (expt |m| 3) (expt |kg| -1) (expt |s| -2))) (define-const |g_| 9.80665 (/ |m| |s| |s|)) (define-const |kB| 1.3806503d-23 (/ J K)) (define-const |NA| 6.0221415d23 (/ |mol|)) (define-const |e0| 8.85418782d-12 (/ F |m|)) (define-const |u0| (* 4 pi 1d-7) (/ H |m|)) (define-const |m_e| 9.1093826d-31 |kg|) (define-const |m_p| 1.672621637d-27 |kg|) (define-const |m_n| 1.674927211d-27 |kg|) (define-unit |u| (* 1.66053886d-27 |kg|)) ;atomic mass unit ;; misc. (define-unit |eV| (* |e| V)) (define-unit |erg| (* 1d-7 J)) (define-unit |g| (* 1/1000 |kg|)) (define-unit |gram| (* 1/1000 |kg|)) (define-unit |ton| (* 1000 |kg|)) ;; (define-unit |km| (* 1000 |m|)) ;このへんがなくても動く ;; (define-unit |cm| (* 1/100 |m|)) ;; (define-unit |mm| (* 1/1000 |m|)) ;; (define-unit |nm| (* 1/1000000 |m|)) (define-unit |angstrom| (* (expt 10 -10) |m|)) (define-unit |litre| (* 1/1000 (expt |m| 3))) (define-unit |l| |litre|) (define-unit |cc| (expt |cm| 3)) ;(defun yard-pound () (define-unit |inch| (* 0.0254 |m|)) (define-unit |feet| (* 12 |inch|)) ;;(define-unit |ft| |feet|) (define-unit |yard| (* 36 |inch|)) ;;(define-unit |yd| |yard|) (define-unit |mile| (* 1760 |yard|)) ;;(define-unit |ml| |mile|) (define-unit |league| (* 3 |mile|)) ; 'yard-pound ; ) (define-unit |barn| (* 100 |fm| |fm|)) (define-unit |Gauss| (* 1/10000 |Tesla|)) (define-unit |atm| (* 101325 |Pa|)) (define-unit |torr| (* 101325/760 |Pa|)) (define-unit |mmHg| (* 133.3224 |Pa|)) (define-unit |ly| (* 9.46073d15 |m|)) (define-unit |AU| (* 1.49598d11 |m|)) (define-unit |pc| (* 3.08568d16 |m|)) (define-unit |minute| (* 60 |s|)) (define-unit |hour| (* 60 |minute|)) (define-unit |day| (* 60 |hour|)) (define-unit |year| (* 365.25 |day|)) (define-const |Celcius| 273.15 K) ;; plack units (define-unit |t_pl| (sqrt (/ (* |hbar| G) (expt |c| 5)))) (define-unit |l_pl| (* |c| |t_pl|)) (define-unit |m_pl| (sqrt (/ (* |hbar| |c|) G))) ;(define-unit |q_pl| (* )) ;(define-unit |T_pl| (* ))
*1:μが打てない環境ではuを使っていいということになっているらしい