* calc/calc-units.el (math-midi-round, math-freqp, math-midip)
[bpt/emacs.git] / lisp / calc / calc-units.el
CommitLineData
8cd8ee52
CW
1;;; calc-units.el --- unit conversion functions for Calc
2
73b0cd50 3;; Copyright (C) 1990-1993, 2001-2011 Free Software Foundation, Inc.
8cd8ee52
CW
4
5;; Author: David Gillespie <daveg@synaptics.com>
e8fff8ed 6;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
136211a9
EZ
7
8;; This file is part of GNU Emacs.
9
662c9c64 10;; GNU Emacs is free software: you can redistribute it and/or modify
7c671b23 11;; it under the terms of the GNU General Public License as published by
662c9c64
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
7c671b23 14
136211a9 15;; GNU Emacs is distributed in the hope that it will be useful,
7c671b23
GM
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
662c9c64 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
136211a9 22
8cd8ee52 23;;; Commentary:
136211a9 24
8cd8ee52 25;;; Code:
136211a9
EZ
26
27;; This file is autoloaded from calc-ext.el.
136211a9 28
7d02e8cd 29(require 'calc-ext)
136211a9 30(require 'calc-macs)
c7388379
JB
31(eval-when-compile
32 (require 'calc-alg))
136211a9 33
8cd8ee52
CW
34;;; Units operations.
35
36;;; Units table last updated 9-Jan-91 by Ulrich Mueller (ulm@vsnhd1.cern.ch)
37;;; with some additions by Przemek Klosowski (przemek@rrdstrad.nist.gov)
ae6bc504 38;;; Updated April 2002 by Jochen Küpper
be59410c 39
a21f3259
JB
40;;; Updated August 2007, using
41;;; CODATA (http://physics.nist.gov/cuu/Constants/index.html)
42;;; NIST (http://physics.nist.gov/Pubs/SP811/appenB9.html)
43;;; ESUWM (Encyclopaedia of Scientific Units, Weights and
ae6bc504 44;;; Measures, by François Cardarelli)
a21f3259 45;;; All conversions are exact unless otherwise noted.
8cd8ee52
CW
46
47(defvar math-standard-units
48 '( ;; Length
cf39c182 49 ( m nil "*Meter" )
60afd99b 50 ( in "254*10^(-2) cm" "Inch" nil
19bdc4d8
JB
51 "2.54 cm")
52 ( ft "12 in" "Foot")
cf39c182
JB
53 ( yd "3 ft" "Yard" )
54 ( mi "5280 ft" "Mile" )
60afd99b 55 ( au "149597870691. m" "Astronomical Unit" nil
19bdc4d8 56 "149597870691 m (*)")
a21f3259
JB
57 ;; (approx) NASA JPL (http://neo.jpl.nasa.gov/glossary/au.html)
58 ( lyr "c yr" "Light Year" )
1265829e 59 ( pc "3.0856775854*10^16 m" "Parsec (**)" nil
ac318df0 60 "3.0856775854 10^16 m (*)") ;; (approx) ESUWM
cf39c182
JB
61 ( nmi "1852 m" "Nautical Mile" )
62 ( fath "6 ft" "Fathom" )
ac318df0 63 ( fur "660 ft" "Furlong")
cf39c182 64 ( mu "1 um" "Micron" )
ac318df0 65 ( mil "(1/1000) in" "Mil" )
1265829e 66 ( point "(1/72) in" "Point (PostScript convention)" )
a21f3259 67 ( Ang "10^(-10) m" "Angstrom" )
cf39c182
JB
68 ( mfi "mi+ft+in" "Miles + feet + inches" )
69 ;; TeX lengths
1265829e
JB
70 ( texpt "(100/7227) in" "Point (TeX convention) (**)" )
71 ( texpc "12 texpt" "Pica (TeX convention) (**)" )
72 ( texbp "point" "Big point (TeX convention) (**)" )
73 ( texdd "(1238/1157) texpt" "Didot point (TeX convention) (**)" )
74 ( texcc "12 texdd" "Cicero (TeX convention) (**)" )
75 ( texsp "(1/65536) texpt" "Scaled TeX point (TeX convention) (**)" )
a1506d29 76
be59410c 77 ;; Area
cf39c182
JB
78 ( hect "10000 m^2" "*Hectare" )
79 ( a "100 m^2" "Are")
ac318df0 80 ( acre "(1/640) mi^2" "Acre" )
a21f3259 81 ( b "10^(-28) m^2" "Barn" )
a1506d29 82
be59410c 83 ;; Volume
a21f3259 84 ( L "10^(-3) m^3" "*Liter" )
cf39c182
JB
85 ( l "L" "Liter" )
86 ( gal "4 qt" "US Gallon" )
87 ( qt "2 pt" "Quart" )
1265829e 88 ( pt "2 cup" "Pint (**)" )
cf39c182
JB
89 ( cup "8 ozfl" "Cup" )
90 ( ozfl "2 tbsp" "Fluid Ounce" )
91 ( floz "2 tbsp" "Fluid Ounce" )
92 ( tbsp "3 tsp" "Tablespoon" )
7026903c
JB
93 ;; ESUWM defines a US gallon as 231 in^3.
94 ;; That gives the following exact value for tsp.
60afd99b 95 ( tsp "492892159375*10^(-11) ml" "Teaspoon" nil
19bdc4d8 96 "4.92892159375 ml")
ac318df0
JB
97 ( vol "tsp+tbsp+ozfl+cup+pt+qt+gal" "Gallons + ... + teaspoons" nil
98 "tsp+tbsp+ozfl+cup+pt+qt+gal")
a21f3259 99 ( galC "galUK" "Canadian Gallon" )
60afd99b 100 ( galUK "454609*10^(-5) L" "UK Gallon" nil
19bdc4d8 101 "4.54609 L") ;; NIST
a1506d29 102
be59410c 103 ;; Time
cf39c182
JB
104 ( s nil "*Second" )
105 ( sec "s" "Second" )
106 ( min "60 s" "Minute" )
107 ( hr "60 min" "Hour" )
108 ( day "24 hr" "Day" )
109 ( wk "7 day" "Week" )
110 ( hms "wk+day+hr+min+s" "Hours, minutes, seconds" )
ac318df0
JB
111 ( yr "36525*10^(-2) day" "Year (Julian)" nil
112 "365.25 day")
cf39c182 113 ( Hz "1/s" "Hertz" )
be59410c
CW
114
115 ;; Speed
cf39c182
JB
116 ( mph "mi/hr" "*Miles per hour" )
117 ( kph "km/hr" "Kilometers per hour" )
118 ( knot "nmi/hr" "Knot" )
a21f3259 119 ( c "299792458 m/s" "Speed of light" ) ;;; CODATA
a1506d29 120
be59410c 121 ;; Acceleration
60afd99b 122 ( ga "980665*10^(-5) m/s^2" "*\"g\" acceleration" nil
19bdc4d8 123 "9.80665 m / s^2") ;; CODATA
be59410c
CW
124
125 ;; Mass
cf39c182
JB
126 ( g nil "*Gram" )
127 ( lb "16 oz" "Pound (mass)" )
60afd99b 128 ( oz "28349523125*10^(-9) g" "Ounce (mass)" nil
19bdc4d8 129 "28.349523125 g") ;; ESUWM
cf39c182
JB
130 ( ton "2000 lb" "Ton" )
131 ( tpo "ton+lb+oz" "Tons + pounds + ounces (mass)" )
132 ( t "1000 kg" "Metric ton" )
60afd99b 133 ( tonUK "10160469088*10^(-7) kg" "UK ton" nil
19bdc4d8 134 "1016.0469088 kg") ;; ESUWM
cf39c182 135 ( lbt "12 ozt" "Troy pound" )
60afd99b 136 ( ozt "311034768*10^(-7) g" "Troy ounce" nil
ac318df0 137 "31.10347680 g") ;; ESUWM, 1/12 exact value for lbt
60afd99b 138 ( ct "(2/10) g" "Carat" nil
19bdc4d8 139 "0.2 g") ;; ESUWM
60afd99b 140 ( u "1.660538782*10^(-27) kg" "Unified atomic mass" nil
ac318df0 141 "1.660538782 10^-27 kg (*)");;(approx) CODATA
be59410c
CW
142
143 ;; Force
cf39c182 144 ( N "m kg/s^2" "*Newton" )
a21f3259 145 ( dyn "10^(-5) N" "Dyne" )
cf39c182 146 ( gf "ga g" "Gram (force)" )
a21f3259 147 ( lbf "ga lb" "Pound (force)" )
cf39c182 148 ( kip "1000 lbf" "Kilopound (force)" )
60afd99b 149 ( pdl "138254954376*10^(-12) N" "Poundal" nil
19bdc4d8 150 "0.138254954376 N") ;; ESUWM
be59410c
CW
151
152 ;; Energy
cf39c182 153 ( J "N m" "*Joule" )
a21f3259 154 ( erg "10^(-7) J" "Erg" )
60afd99b 155 ( cal "41868*10^(-4) J" "International Table Calorie" nil
ac318df0 156 "4.1868 J") ;; NIST
60afd99b 157 ( calth "4184*10^(-3) J" "Thermochemical Calorie" nil
ac318df0
JB
158 "4.184 J") ;; NIST
159 ( Cal "1000 cal" "Large Calorie")
60afd99b 160 ( Btu "105505585262*10^(-8) J" "International Table Btu" nil
19bdc4d8 161 "1055.05585262 J") ;; ESUWM
cf39c182
JB
162 ( eV "ech V" "Electron volt" )
163 ( ev "eV" "Electron volt" )
164 ( therm "105506000 J" "EEC therm" )
165 ( invcm "h c/cm" "Energy in inverse centimeters" )
166 ( Kayser "invcm" "Kayser (inverse centimeter energy)" )
167 ( men "100/invcm" "Inverse energy in meters" )
168 ( Hzen "h Hz" "Energy in Hertz")
169 ( Ken "k K" "Energy in Kelvins")
02bf5ab9 170 ( Wh "W hr" "Watt hour")
cf39c182 171 ( Ws "W s" "Watt second")
be59410c
CW
172
173 ;; Power
cf39c182 174 ( W "J/s" "*Watt" )
ac318df0
JB
175 ( hp "550 ft lbf/s" "Horsepower") ;;ESUWM
176 ( hpm "75 m kgf/s" "Metric Horsepower") ;;ESUWM
be59410c
CW
177
178 ;; Temperature
cf39c182
JB
179 ( K nil "*Degree Kelvin" K )
180 ( dK "K" "Degree Kelvin" K )
181 ( degK "K" "Degree Kelvin" K )
182 ( dC "K" "Degree Celsius" C )
183 ( degC "K" "Degree Celsius" C )
184 ( dF "(5/9) K" "Degree Fahrenheit" F )
185 ( degF "(5/9) K" "Degree Fahrenheit" F )
be59410c
CW
186
187 ;; Pressure
cf39c182 188 ( Pa "N/m^2" "*Pascal" )
a21f3259
JB
189 ( bar "10^5 Pa" "Bar" )
190 ( atm "101325 Pa" "Standard atmosphere" ) ;; CODATA
ac318df0 191 ( Torr "(1/760) atm" "Torr")
cf39c182 192 ( mHg "1000 Torr" "Meter of mercury" )
60afd99b 193 ( inHg "254*10^(-1) mmHg" "Inch of mercury" nil
19bdc4d8 194 "25.4 mmHg")
60afd99b 195 ( inH2O "2.490889*10^2 Pa" "Inch of water" nil
ac318df0 196 "2.490889 10^2 Pa (*)") ;;(approx) NIST
a21f3259 197 ( psi "lbf/in^2" "Pounds per square inch" )
be59410c
CW
198
199 ;; Viscosity
a21f3259
JB
200 ( P "(1/10) Pa s" "*Poise" )
201 ( St "10^(-4) m^2/s" "Stokes" )
be59410c
CW
202
203 ;; Electromagnetism
cf39c182
JB
204 ( A nil "*Ampere" )
205 ( C "A s" "Coulomb" )
206 ( Fdy "ech Nav" "Faraday" )
a21f3259 207 ( e "ech" "Elementary charge" )
60afd99b 208 ( ech "1.602176487*10^(-19) C" "Elementary charge" nil
ac318df0 209 "1.602176487 10^-19 C (*)") ;;(approx) CODATA
cf39c182
JB
210 ( V "W/A" "Volt" )
211 ( ohm "V/A" "Ohm" )
ae6bc504 212 ( Ω "ohm" "Ohm" )
cf39c182
JB
213 ( mho "A/V" "Mho" )
214 ( S "A/V" "Siemens" )
215 ( F "C/V" "Farad" )
216 ( H "Wb/A" "Henry" )
217 ( T "Wb/m^2" "Tesla" )
a21f3259 218 ( Gs "10^(-4) T" "Gauss" )
cf39c182 219 ( Wb "V s" "Weber" )
be59410c
CW
220
221 ;; Luminous intensity
cf39c182 222 ( cd nil "*Candela" )
a21f3259 223 ( sb "10000 cd/m^2" "Stilb" )
cf39c182
JB
224 ( lm "cd sr" "Lumen" )
225 ( lx "lm/m^2" "Lux" )
a21f3259 226 ( ph "10000 lx" "Phot" )
ac318df0 227 ( fc "lm/ft^2" "Footcandle") ;; ESUWM
a21f3259 228 ( lam "10000 lm/m^2" "Lambert" )
ac318df0 229 ( flam "(1/pi) cd/ft^2" "Footlambert") ;; ESUWM
be59410c
CW
230
231 ;; Radioactivity
cf39c182 232 ( Bq "1/s" "*Becquerel" )
a21f3259 233 ( Ci "37*10^9 Bq" "Curie" ) ;; ESUWM
cf39c182
JB
234 ( Gy "J/kg" "Gray" )
235 ( Sv "Gy" "Sievert" )
a21f3259
JB
236 ( R "258*10^(-6) C/kg" "Roentgen" ) ;; NIST
237 ( rd "(1/100) Gy" "Rad" )
cf39c182 238 ( rem "rd" "Rem" )
be59410c
CW
239
240 ;; Amount of substance
cf39c182 241 ( mol nil "*Mole" )
be59410c
CW
242
243 ;; Plane angle
cf39c182
JB
244 ( rad nil "*Radian" )
245 ( circ "2 pi rad" "Full circle" )
246 ( rev "circ" "Full revolution" )
247 ( deg "circ/360" "Degree" )
248 ( arcmin "deg/60" "Arc minute" )
249 ( arcsec "arcmin/60" "Arc second" )
250 ( grad "circ/400" "Grade" )
251 ( rpm "rev/min" "Revolutions per minute" )
be59410c
CW
252
253 ;; Solid angle
cf39c182 254 ( sr nil "*Steradian" )
be59410c 255
cf39c182 256 ;; Other physical quantities
a21f3259 257 ;; The values are from CODATA, and are approximate.
60afd99b 258 ( h "6.62606896*10^(-34) J s" "*Planck's constant" nil
ac318df0
JB
259 "6.62606896 10^-34 J s (*)")
260 ( hbar "h / (2 pi)" "Planck's constant" ) ;; Exact
261 ( mu0 "4 pi 10^(-7) H/m" "Permeability of vacuum") ;; Exact
ae6bc504 262 ( μ0 "mu0" "Permeability of vacuum") ;; Exact
4929aa69 263 ( eps0 "1 / (mu0 c^2)" "Permittivity of vacuum" )
ae6bc504 264 ( ε0 "eps0" "Permittivity of vacuum" )
60afd99b 265 ( G "6.67428*10^(-11) m^3/(kg s^2)" "Gravitational constant" nil
9b3e5667 266 "6.67428 10^-11 m^3/(kg s^2) (*)")
60afd99b 267 ( Nav "6.02214179*10^(23) / mol" "Avogadro's constant" nil
ac318df0 268 "6.02214179 10^23 / mol (*)")
60afd99b 269 ( me "9.10938215*10^(-31) kg" "Electron rest mass" nil
ac318df0 270 "9.10938215 10^-31 kg (*)")
60afd99b 271 ( mp "1.672621637*10^(-27) kg" "Proton rest mass" nil
ac318df0 272 "1.672621637 10^-27 kg (*)")
60afd99b 273 ( mn "1.674927211*10^(-27) kg" "Neutron rest mass" nil
ac318df0 274 "1.674927211 10^-27 kg (*)")
60afd99b 275 ( mmu "1.88353130*10^(-28) kg" "Muon rest mass" nil
ac318df0 276 "1.88353130 10^-28 kg (*)")
ae6bc504
JB
277 ( mμ "mmu" "Muon rest mass" nil
278 "1.88353130 10^-28 kg (*)")
60afd99b 279 ( Ryd "10973731.568527 /m" "Rydberg's constant" nil
19bdc4d8 280 "10973731.568527 /m (*)")
60afd99b 281 ( k "1.3806504*10^(-23) J/K" "Boltzmann's constant" nil
ac318df0 282 "1.3806504 10^-23 J/K (*)")
60afd99b 283 ( alpha "7.2973525376*10^(-3)" "Fine structure constant" nil
ac318df0 284 "7.2973525376 10^-3 (*)")
ae6bc504
JB
285 ( α "alpha" "Fine structure constant" nil
286 "7.2973525376 10^-3 (*)")
60afd99b 287 ( muB "927.400915*10^(-26) J/T" "Bohr magneton" nil
ac318df0 288 "927.400915 10^-26 J/T (*)")
60afd99b 289 ( muN "5.05078324*10^(-27) J/T" "Nuclear magneton" nil
ac318df0 290 "5.05078324 10^-27 J/T (*)")
60afd99b 291 ( mue "-928.476377*10^(-26) J/T" "Electron magnetic moment" nil
ac318df0 292 "-928.476377 10^-26 J/T (*)")
60afd99b 293 ( mup "1.410606662*10^(-26) J/T" "Proton magnetic moment" nil
ac318df0 294 "1.410606662 10^-26 J/T (*)")
60afd99b 295 ( R0 "8.314472 J/(mol K)" "Molar gas constant" nil
19bdc4d8 296 "8.314472 J/(mol K) (*)")
60afd99b 297 ( V0 "22.710981*10^(-3) m^3/mol" "Standard volume of ideal gas" nil
603823f5
JB
298 "22.710981 10^-3 m^3/mol (*)")
299 ;; Logarithmic units
300 ( Np nil "*Neper")
301 ( dB "(ln(10)/20) Np" "decibel")))
8cd8ee52
CW
302
303
304(defvar math-additional-units nil
305 "*Additional units table for user-defined units.
60afd99b 306Must be formatted like `math-standard-units'.
11220394 307If you change this, be sure to set `math-units-table' to nil to ensure
8cd8ee52
CW
308that the combined units table will be rebuilt.")
309
310(defvar math-unit-prefixes
a21f3259
JB
311 '( ( ?Y (^ 10 24) "Yotta" )
312 ( ?Z (^ 10 21) "Zetta" )
313 ( ?E (^ 10 18) "Exa" )
314 ( ?P (^ 10 15) "Peta" )
315 ( ?T (^ 10 12) "Tera" )
316 ( ?G (^ 10 9) "Giga" )
317 ( ?M (^ 10 6) "Mega" )
318 ( ?k (^ 10 3) "Kilo" )
319 ( ?K (^ 10 3) "Kilo" )
320 ( ?h (^ 10 2) "Hecto" )
321 ( ?H (^ 10 2) "Hecto" )
322 ( ?D (^ 10 1) "Deka" )
323 ( 0 (^ 10 0) nil )
324 ( ?d (^ 10 -1) "Deci" )
325 ( ?c (^ 10 -2) "Centi" )
326 ( ?m (^ 10 -3) "Milli" )
327 ( ?u (^ 10 -6) "Micro" )
be19ef0b 328 ( ?μ (^ 10 -6) "Micro" )
a21f3259
JB
329 ( ?n (^ 10 -9) "Nano" )
330 ( ?p (^ 10 -12) "Pico" )
331 ( ?f (^ 10 -15) "Femto" )
332 ( ?a (^ 10 -18) "Atto" )
333 ( ?z (^ 10 -21) "zepto" )
334 ( ?y (^ 10 -24) "yocto" )))
8cd8ee52
CW
335
336(defvar math-standard-units-systems
337 '( ( base nil )
a21f3259
JB
338 ( si ( ( g '(/ (var kg var-kg) 1000) ) ) )
339 ( mks ( ( g '(/ (var kg var-kg) 1000) ) ) )
340 ( cgs ( ( m '(* (var cm var-cm) 100 ) ) ) )))
8cd8ee52
CW
341
342(defvar math-units-table nil
60afd99b
JB
343 "Internal units table.
344Derived from `math-standard-units' and `math-additional-units'.
8cd8ee52
CW
345Entries are (SYMBOL EXPR DOC-STRING TEMP-TYPE BASE-UNITS).")
346
347(defvar math-units-table-buffer-valid nil)
136211a9
EZ
348
349;;; Units commands.
350
351(defun calc-base-units ()
352 (interactive)
353 (calc-slow-wrapper
354 (let ((calc-autorange-units nil))
355 (calc-enter-result 1 "bsun" (math-simplify-units
356 (math-to-standard-units (calc-top-n 1)
c9aef719 357 nil))))))
136211a9
EZ
358
359(defun calc-quick-units ()
360 (interactive)
361 (calc-slow-wrapper
e93c003e 362 (let* ((num (- last-command-event ?0))
136211a9
EZ
363 (pos (if (= num 0) 10 num))
364 (units (calc-var-value 'var-Units))
365 (expr (calc-top-n 1)))
8cd8ee52 366 (unless (and (>= num 0) (<= num 9))
91af11b2 367 (error "Bad unit number"))
8cd8ee52 368 (unless (math-vectorp units)
91af11b2 369 (error "No \"quick units\" are defined"))
8cd8ee52 370 (unless (< pos (length units))
91af11b2 371 (error "Unit number %d not defined" pos))
136211a9
EZ
372 (if (math-units-in-expr-p expr nil)
373 (calc-enter-result 1 (format "cun%d" num)
374 (math-convert-units expr (nth pos units)))
375 (calc-enter-result 1 (format "*un%d" num)
376 (math-simplify-units
c9aef719 377 (math-mul expr (nth pos units))))))))
136211a9 378
5360ea16
JB
379(defun math-get-standard-units (expr)
380 "Return the standard units in EXPR."
381 (math-simplify-units
382 (math-extract-units
383 (math-to-standard-units expr nil))))
384
385(defun math-get-units (expr)
386 "Return the units in EXPR."
387 (math-simplify-units
388 (math-extract-units expr)))
389
390(defun math-make-unit-string (expr)
391 "Return EXPR in string form.
392If EXPR is nil, return nil."
393 (if expr
394 (let ((cexpr (math-compose-expr expr 0)))
09040c8d 395 (replace-regexp-in-string
a21f3259
JB
396 " / " "/"
397 (if (stringp cexpr)
398 cexpr
399 (math-composition-to-string cexpr))))))
5360ea16 400
09040c8d 401(defvar math-default-units-table
5360ea16
JB
402 (make-hash-table :test 'equal)
403 "A table storing previously converted units.")
404
405(defun math-get-default-units (expr)
406 "Get default units to use when converting the units in EXPR."
407 (let* ((units (math-get-units expr))
408 (standard-units (math-get-standard-units expr))
09040c8d 409 (default-units (gethash
5360ea16
JB
410 standard-units
411 math-default-units-table)))
412 (if (equal units (car default-units))
413 (math-make-unit-string (cadr default-units))
414 (math-make-unit-string (car default-units)))))
415
416(defun math-put-default-units (expr)
417 "Put the units in EXPR in the default units table."
418 (let* ((units (math-get-units expr))
419 (standard-units (math-get-standard-units expr))
420 (default-units (gethash
421 standard-units
422 math-default-units-table)))
423 (cond
424 ((not default-units)
425 (puthash standard-units (list units) math-default-units-table))
426 ((not (equal units (car default-units)))
427 (puthash standard-units
428 (list units (car default-units))
429 math-default-units-table)))))
430
431
136211a9
EZ
432(defun calc-convert-units (&optional old-units new-units)
433 (interactive)
434 (calc-slow-wrapper
435 (let ((expr (calc-top-n 1))
436 (uoldname nil)
27971241 437 unew
5360ea16
JB
438 units
439 defunits)
8cd8ee52
CW
440 (unless (math-units-in-expr-p expr t)
441 (let ((uold (or old-units
442 (progn
443 (setq uoldname (read-string "Old units: "))
444 (if (equal uoldname "")
445 (progn
446 (setq uoldname "1")
447 1)
448 (if (string-match "\\` */" uoldname)
449 (setq uoldname (concat "1" uoldname)))
450 (math-read-expr uoldname))))))
451 (when (eq (car-safe uold) 'error)
452 (error "Bad format in units expression: %s" (nth 1 uold)))
453 (setq expr (math-mul expr uold))))
454 (unless new-units
5360ea16 455 (setq defunits (math-get-default-units expr))
09040c8d 456 (setq new-units
5360ea16
JB
457 (read-string (concat
458 (if uoldname
459 (concat "Old units: "
460 uoldname
461 ", new units")
462 "New units")
463 (if defunits
464 (concat
0f3955d9 465 " (default "
5360ea16
JB
466 defunits
467 "): ")
468 ": "))))
09040c8d 469
5360ea16
JB
470 (if (and
471 (string= new-units "")
472 defunits)
473 (setq new-units defunits)))
8cd8ee52
CW
474 (when (string-match "\\` */" new-units)
475 (setq new-units (concat "1" new-units)))
136211a9 476 (setq units (math-read-expr new-units))
8cd8ee52
CW
477 (when (eq (car-safe units) 'error)
478 (error "Bad format in units expression: %s" (nth 2 units)))
5360ea16 479 (math-put-default-units units)
136211a9
EZ
480 (let ((unew (math-units-in-expr-p units t))
481 (std (and (eq (car-safe units) 'var)
482 (assq (nth 1 units) math-standard-units-systems))))
483 (if std
484 (calc-enter-result 1 "cvun" (math-simplify-units
485 (math-to-standard-units expr
486 (nth 1 std))))
8cd8ee52
CW
487 (unless unew
488 (error "No units specified"))
136211a9
EZ
489 (calc-enter-result 1 "cvun"
490 (math-convert-units
491 expr units
c9aef719 492 (and uoldname (not (equal uoldname "1"))))))))))
136211a9
EZ
493
494(defun calc-autorange-units (arg)
495 (interactive "P")
496 (calc-wrapper
497 (calc-change-mode 'calc-autorange-units arg nil t)
498 (message (if calc-autorange-units
8cd8ee52
CW
499 "Adjusting target unit prefix automatically"
500 "Using target units exactly"))))
136211a9
EZ
501
502(defun calc-convert-temperature (&optional old-units new-units)
503 (interactive)
504 (calc-slow-wrapper
505 (let ((expr (calc-top-n 1))
506 (uold nil)
507 (uoldname nil)
5360ea16
JB
508 unew
509 defunits)
136211a9
EZ
510 (setq uold (or old-units
511 (let ((units (math-single-units-in-expr-p expr)))
512 (if units
513 (if (consp units)
514 (list 'var (car units)
515 (intern (concat "var-"
516 (symbol-name
517 (car units)))))
518 (error "Not a pure temperature expression"))
519 (math-read-expr
520 (setq uoldname (read-string
521 "Old temperature units: ")))))))
8cd8ee52
CW
522 (when (eq (car-safe uold) 'error)
523 (error "Bad format in units expression: %s" (nth 2 uold)))
136211a9
EZ
524 (or (math-units-in-expr-p expr nil)
525 (setq expr (math-mul expr uold)))
5360ea16 526 (setq defunits (math-get-default-units expr))
136211a9 527 (setq unew (or new-units
fa786329
JB
528 (read-string
529 (concat
530 (if uoldname
531 (concat "Old temperature units: "
532 uoldname
533 ", new units")
534 "New temperature units")
535 (if defunits
536 (concat " (default "
537 defunits
538 "): ")
539 ": ")))))
540 (setq unew (math-read-expr (if (string= unew "") defunits unew)))
8cd8ee52
CW
541 (when (eq (car-safe unew) 'error)
542 (error "Bad format in units expression: %s" (nth 2 unew)))
5360ea16 543 (math-put-default-units unew)
a34f800f
JB
544 (let ((ntemp (calc-normalize
545 (math-simplify-units
546 (math-convert-temperature expr uold unew
547 uoldname)))))
548 (if (Math-zerop ntemp)
549 (setq ntemp (list '* ntemp unew)))
550 (let ((calc-simplify-mode 'none))
551 (calc-enter-result 1 "cvtm" ntemp))))))
136211a9
EZ
552
553(defun calc-remove-units ()
554 (interactive)
555 (calc-slow-wrapper
556 (calc-enter-result 1 "rmun" (math-simplify-units
c9aef719 557 (math-remove-units (calc-top-n 1))))))
136211a9
EZ
558
559(defun calc-extract-units ()
560 (interactive)
561 (calc-slow-wrapper
562 (calc-enter-result 1 "rmun" (math-simplify-units
c9aef719 563 (math-extract-units (calc-top-n 1))))))
136211a9 564
09040c8d 565;; The variables calc-num-units and calc-den-units are local to
27971241
JB
566;; calc-explain-units, but are used by calc-explain-units-rec,
567;; which is called by calc-explain-units.
568(defvar calc-num-units)
569(defvar calc-den-units)
570
136211a9
EZ
571(defun calc-explain-units ()
572 (interactive)
573 (calc-wrapper
27971241
JB
574 (let ((calc-num-units nil)
575 (calc-den-units nil))
136211a9 576 (calc-explain-units-rec (calc-top-n 1) 1)
27971241
JB
577 (and calc-den-units (string-match "^[^(].* .*[^)]$" calc-den-units)
578 (setq calc-den-units (concat "(" calc-den-units ")")))
579 (if calc-num-units
580 (if calc-den-units
581 (message "%s per %s" calc-num-units calc-den-units)
582 (message "%s" calc-num-units))
583 (if calc-den-units
584 (message "1 per %s" calc-den-units)
c9aef719 585 (message "No units in expression"))))))
136211a9
EZ
586
587(defun calc-explain-units-rec (expr pow)
588 (let ((u (math-check-unit-name expr))
589 pos)
590 (if (and u (not (math-zerop pow)))
591 (let ((name (or (nth 2 u) (symbol-name (car u)))))
592 (if (eq (aref name 0) ?\*)
593 (setq name (substring name 1)))
ae6bc504
JB
594 (if (string-match "[^a-zA-Zα-ωΑ-Ω0-9']" name)
595 (if (string-match "^[a-zA-Zα-ωΑ-Ω0-9' ()]*$" name)
136211a9
EZ
596 (while (setq pos (string-match "[ ()]" name))
597 (setq name (concat (substring name 0 pos)
598 (if (eq (aref name pos) 32) "-" "")
599 (substring name (1+ pos)))))
600 (setq name (concat "(" name ")"))))
601 (or (eq (nth 1 expr) (car u))
602 (setq name (concat (nth 2 (assq (aref (symbol-name
603 (nth 1 expr)) 0)
604 math-unit-prefixes))
ae6bc504 605 (if (and (string-match "[^a-zA-Zα-ωΑ-Ω0-9']" name)
136211a9
EZ
606 (not (memq (car u) '(mHg gf))))
607 (concat "-" name)
608 (downcase name)))))
609 (cond ((or (math-equal-int pow 1)
610 (math-equal-int pow -1)))
611 ((or (math-equal-int pow 2)
612 (math-equal-int pow -2))
613 (if (equal (nth 4 u) '((m . 1)))
614 (setq name (concat "Square-" name))
615 (setq name (concat name "-squared"))))
616 ((or (math-equal-int pow 3)
617 (math-equal-int pow -3))
618 (if (equal (nth 4 u) '((m . 1)))
619 (setq name (concat "Cubic-" name))
620 (setq name (concat name "-cubed"))))
621 (t
622 (setq name (concat name "^"
623 (math-format-number (math-abs pow))))))
624 (if (math-posp pow)
27971241
JB
625 (setq calc-num-units (if calc-num-units
626 (concat calc-num-units " " name)
136211a9 627 name))
27971241
JB
628 (setq calc-den-units (if calc-den-units
629 (concat calc-den-units " " name)
136211a9
EZ
630 name))))
631 (cond ((eq (car-safe expr) '*)
632 (calc-explain-units-rec (nth 1 expr) pow)
633 (calc-explain-units-rec (nth 2 expr) pow))
634 ((eq (car-safe expr) '/)
635 (calc-explain-units-rec (nth 1 expr) pow)
636 (calc-explain-units-rec (nth 2 expr) (- pow)))
637 ((memq (car-safe expr) '(neg + -))
638 (calc-explain-units-rec (nth 1 expr) pow))
639 ((and (eq (car-safe expr) '^)
640 (math-realp (nth 2 expr)))
641 (calc-explain-units-rec (nth 1 expr)
c9aef719 642 (math-mul pow (nth 2 expr))))))))
136211a9
EZ
643
644(defun calc-simplify-units ()
645 (interactive)
646 (calc-slow-wrapper
647 (calc-with-default-simplification
c9aef719 648 (calc-enter-result 1 "smun" (math-simplify-units (calc-top-n 1))))))
136211a9
EZ
649
650(defun calc-view-units-table (n)
651 (interactive "P")
652 (and n (setq math-units-table-buffer-valid nil))
653 (let ((win (get-buffer-window "*Units Table*")))
654 (if (and win
655 math-units-table
656 math-units-table-buffer-valid)
657 (progn
658 (bury-buffer (window-buffer win))
659 (let ((curwin (selected-window)))
660 (select-window win)
661 (switch-to-buffer nil)
662 (select-window curwin)))
c9aef719 663 (math-build-units-table-buffer nil))))
136211a9
EZ
664
665(defun calc-enter-units-table (n)
666 (interactive "P")
667 (and n (setq math-units-table-buffer-valid nil))
668 (math-build-units-table-buffer t)
5c08522d 669 (message "%s" (substitute-command-keys "Type \\[calc] to return to the Calculator")))
136211a9 670
19bdc4d8
JB
671(defun calc-define-unit (uname desc &optional disp)
672 (interactive "SDefine unit name: \nsDescription: \nP")
673 (if disp (setq disp (read-string "Display definition: ")))
136211a9
EZ
674 (calc-wrapper
675 (let ((form (calc-top-n 1))
676 (unit (assq uname math-additional-units)))
677 (or unit
678 (setq math-additional-units
19bdc4d8 679 (cons (setq unit (list uname nil nil nil nil))
136211a9
EZ
680 math-additional-units)
681 math-units-table nil))
682 (setcar (cdr unit) (and (not (and (eq (car-safe form) 'var)
683 (eq (nth 1 form) uname)))
684 (not (math-equal-int form 1))
685 (math-format-flat-expr form 0)))
686 (setcar (cdr (cdr unit)) (and (not (equal desc ""))
19bdc4d8
JB
687 desc))
688 (if disp
689 (setcar (cdr (cdr (cdr (cdr unit)))) disp))))
c9aef719 690 (calc-invalidate-units-table))
136211a9
EZ
691
692(defun calc-undefine-unit (uname)
693 (interactive "SUndefine unit name: ")
694 (calc-wrapper
695 (let ((unit (assq uname math-additional-units)))
696 (or unit
697 (if (assq uname math-standard-units)
698 (error "\"%s\" is a predefined unit name" uname)
699 (error "Unit name \"%s\" not found" uname)))
700 (setq math-additional-units (delq unit math-additional-units)
701 math-units-table nil)))
c9aef719 702 (calc-invalidate-units-table))
136211a9
EZ
703
704(defun calc-invalidate-units-table ()
705 (setq math-units-table nil)
706 (let ((buf (get-buffer "*Units Table*")))
707 (and buf
6df9b6d7 708 (with-current-buffer buf
136211a9
EZ
709 (save-excursion
710 (goto-char (point-min))
711 (if (looking-at "Calculator Units Table")
ed8060d9 712 (let ((inhibit-read-only t))
c9aef719 713 (insert "(Obsolete) "))))))))
136211a9
EZ
714
715(defun calc-get-unit-definition (uname)
716 (interactive "SGet definition for unit: ")
717 (calc-wrapper
718 (math-build-units-table)
719 (let ((unit (assq uname math-units-table)))
720 (or unit
721 (error "Unit name \"%s\" not found" uname))
722 (let ((msg (nth 2 unit)))
723 (if (stringp msg)
724 (if (string-match "^\\*" msg)
725 (setq msg (substring msg 1)))
726 (setq msg (symbol-name uname)))
727 (if (nth 1 unit)
728 (progn
729 (calc-enter-result 0 "ugdf" (nth 1 unit))
730 (message "Derived unit: %s" msg))
731 (calc-enter-result 0 "ugdf" (list 'var uname
732 (intern
733 (concat "var-"
734 (symbol-name uname)))))
c9aef719 735 (message "Base unit: %s" msg))))))
136211a9
EZ
736
737(defun calc-permanent-units ()
738 (interactive)
739 (calc-wrapper
740 (let (pos)
741 (set-buffer (find-file-noselect (substitute-in-file-name
742 calc-settings-file)))
743 (goto-char (point-min))
744 (if (and (search-forward ";;; Custom units stored by Calc" nil t)
745 (progn
746 (beginning-of-line)
747 (setq pos (point))
748 (search-forward "\n;;; End of custom units" nil t)))
749 (progn
750 (beginning-of-line)
751 (forward-line 1)
752 (delete-region pos (point)))
753 (goto-char (point-max))
754 (insert "\n\n")
755 (forward-char -1))
756 (insert ";;; Custom units stored by Calc on " (current-time-string) "\n")
757 (if math-additional-units
758 (progn
759 (insert "(setq math-additional-units '(\n")
760 (let ((list math-additional-units))
761 (while list
762 (insert " (" (symbol-name (car (car list))) " "
763 (if (nth 1 (car list))
764 (if (stringp (nth 1 (car list)))
765 (prin1-to-string (nth 1 (car list)))
766 (prin1-to-string (math-format-flat-expr
767 (nth 1 (car list)) 0)))
768 "nil")
769 " "
770 (prin1-to-string (nth 2 (car list)))
771 ")\n")
772 (setq list (cdr list))))
773 (insert "))\n"))
774 (insert ";;; (no custom units defined)\n"))
775 (insert ";;; End of custom units\n")
c9aef719 776 (save-buffer))))
136211a9
EZ
777
778
27971241
JB
779;; The variable math-cu-unit-list is local to math-build-units-table,
780;; but is used by math-compare-unit-names, which is called (indirectly)
781;; by math-build-units-table.
782;; math-cu-unit-list is also local to math-convert-units, but is used
783;; by math-convert-units-rec, which is called by math-convert-units.
784(defvar math-cu-unit-list)
136211a9 785
136211a9
EZ
786(defun math-build-units-table ()
787 (or math-units-table
788 (let* ((combined-units (append math-additional-units
789 math-standard-units))
27971241 790 (math-cu-unit-list (mapcar 'car combined-units))
136211a9
EZ
791 tab)
792 (message "Building units table...")
793 (setq math-units-table-buffer-valid nil)
794 (setq tab (mapcar (function
795 (lambda (x)
796 (list (car x)
797 (and (nth 1 x)
798 (if (stringp (nth 1 x))
799 (let ((exp (math-read-plain-expr
800 (nth 1 x))))
801 (if (eq (car-safe exp) 'error)
802 (error "Format error in definition of %s in units table: %s"
803 (car x) (nth 2 exp))
804 exp))
805 (nth 1 x)))
806 (nth 2 x)
807 (nth 3 x)
808 (and (not (nth 1 x))
19bdc4d8
JB
809 (list (cons (car x) 1)))
810 (nth 4 x))))
136211a9
EZ
811 combined-units))
812 (let ((math-units-table tab))
09040c8d 813 (mapc 'math-find-base-units tab))
136211a9 814 (message "Building units table...done")
c9aef719 815 (setq math-units-table tab))))
136211a9 816
27971241
JB
817;; The variables math-fbu-base and math-fbu-entry are local to
818;; math-find-base-units, but are used by math-find-base-units-rec,
819;; which is called by math-find-base-units.
820(defvar math-fbu-base)
821(defvar math-fbu-entry)
822
3effaa28
JB
823(defun math-find-base-units (math-fbu-entry)
824 (if (eq (nth 4 math-fbu-entry) 'boom)
825 (error "Circular definition involving unit %s" (car math-fbu-entry)))
826 (or (nth 4 math-fbu-entry)
827 (let (math-fbu-base)
828 (setcar (nthcdr 4 math-fbu-entry) 'boom)
829 (math-find-base-units-rec (nth 1 math-fbu-entry) 1)
830 '(or math-fbu-base
831 (error "Dimensionless definition for unit %s" (car math-fbu-entry)))
832 (while (eq (cdr (car math-fbu-base)) 0)
833 (setq math-fbu-base (cdr math-fbu-base)))
834 (let ((b math-fbu-base))
136211a9
EZ
835 (while (cdr b)
836 (if (eq (cdr (car (cdr b))) 0)
837 (setcdr b (cdr (cdr b)))
838 (setq b (cdr b)))))
3effaa28
JB
839 (setq math-fbu-base (sort math-fbu-base 'math-compare-unit-names))
840 (setcar (nthcdr 4 math-fbu-entry) math-fbu-base)
841 math-fbu-base)))
136211a9
EZ
842
843(defun math-compare-unit-names (a b)
27971241 844 (memq (car b) (cdr (memq (car a) math-cu-unit-list))))
136211a9
EZ
845
846(defun math-find-base-units-rec (expr pow)
847 (let ((u (math-check-unit-name expr)))
848 (cond (u
849 (let ((ulist (math-find-base-units u)))
850 (while ulist
851 (let ((p (* (cdr (car ulist)) pow))
3effaa28 852 (old (assq (car (car ulist)) math-fbu-base)))
136211a9
EZ
853 (if old
854 (setcdr old (+ (cdr old) p))
09040c8d 855 (setq math-fbu-base
3effaa28 856 (cons (cons (car (car ulist)) p) math-fbu-base))))
136211a9
EZ
857 (setq ulist (cdr ulist)))))
858 ((math-scalarp expr))
859 ((and (eq (car expr) '^)
860 (integerp (nth 2 expr)))
861 (math-find-base-units-rec (nth 1 expr) (* pow (nth 2 expr))))
862 ((eq (car expr) '*)
863 (math-find-base-units-rec (nth 1 expr) pow)
864 (math-find-base-units-rec (nth 2 expr) pow))
865 ((eq (car expr) '/)
866 (math-find-base-units-rec (nth 1 expr) pow)
867 (math-find-base-units-rec (nth 2 expr) (- pow)))
868 ((eq (car expr) 'neg)
869 (math-find-base-units-rec (nth 1 expr) pow))
870 ((eq (car expr) '+)
871 (math-find-base-units-rec (nth 1 expr) pow))
872 ((eq (car expr) 'var)
873 (or (eq (nth 1 expr) 'pi)
874 (error "Unknown name %s in defining expression for unit %s"
3effaa28 875 (nth 1 expr) (car math-fbu-entry))))
603823f5 876 ((equal expr '(calcFunc-ln 10)))
3effaa28 877 (t (error "Malformed defining expression for unit %s" (car math-fbu-entry))))))
136211a9
EZ
878
879
880(defun math-units-in-expr-p (expr sub-exprs)
881 (and (consp expr)
882 (if (eq (car expr) 'var)
883 (math-check-unit-name expr)
884 (and (or sub-exprs
885 (memq (car expr) '(* / ^)))
886 (or (math-units-in-expr-p (nth 1 expr) sub-exprs)
c9aef719 887 (math-units-in-expr-p (nth 2 expr) sub-exprs))))))
136211a9
EZ
888
889(defun math-only-units-in-expr-p (expr)
890 (and (consp expr)
891 (if (eq (car expr) 'var)
892 (math-check-unit-name expr)
893 (if (memq (car expr) '(* /))
894 (and (math-only-units-in-expr-p (nth 1 expr))
895 (math-only-units-in-expr-p (nth 2 expr)))
896 (and (eq (car expr) '^)
897 (and (math-only-units-in-expr-p (nth 1 expr))
c9aef719 898 (math-realp (nth 2 expr))))))))
136211a9
EZ
899
900(defun math-single-units-in-expr-p (expr)
901 (cond ((math-scalarp expr) nil)
902 ((eq (car expr) 'var)
903 (math-check-unit-name expr))
904 ((eq (car expr) '*)
905 (let ((u1 (math-single-units-in-expr-p (nth 1 expr)))
906 (u2 (math-single-units-in-expr-p (nth 2 expr))))
907 (or (and u1 u2 'wrong)
908 u1
909 u2)))
910 ((eq (car expr) '/)
911 (if (math-units-in-expr-p (nth 2 expr) nil)
912 'wrong
913 (math-single-units-in-expr-p (nth 1 expr))))
c9aef719 914 (t 'wrong)))
136211a9
EZ
915
916(defun math-check-unit-name (v)
917 (and (eq (car-safe v) 'var)
918 (or (assq (nth 1 v) (or math-units-table (math-build-units-table)))
919 (let ((name (symbol-name (nth 1 v))))
920 (and (> (length name) 1)
921 (assq (aref name 0) math-unit-prefixes)
922 (or (assq (intern (substring name 1)) math-units-table)
923 (and (eq (aref name 0) ?M)
924 (> (length name) 3)
925 (eq (aref name 1) ?e)
926 (eq (aref name 2) ?g)
927 (assq (intern (substring name 3))
c9aef719 928 math-units-table))))))))
136211a9 929
27971241
JB
930;; The variable math-which-standard is local to math-to-standard-units,
931;; but is used by math-to-standard-rec, which is called by
932;; math-to-standard-units.
933(defvar math-which-standard)
136211a9 934
27971241 935(defun math-to-standard-units (expr math-which-standard)
c9aef719 936 (math-to-standard-rec expr))
136211a9
EZ
937
938(defun math-to-standard-rec (expr)
939 (if (eq (car-safe expr) 'var)
940 (let ((u (math-check-unit-name expr))
941 (base (nth 1 expr)))
942 (if u
943 (progn
944 (if (nth 1 u)
945 (setq expr (math-to-standard-rec (nth 1 u)))
27971241 946 (let ((st (assq (car u) math-which-standard)))
136211a9
EZ
947 (if st
948 (setq expr (nth 1 st))
949 (setq expr (list 'var (car u)
950 (intern (concat "var-"
951 (symbol-name
952 (car u)))))))))
953 (or (null u)
954 (eq base (car u))
955 (setq expr (list '*
956 (nth 1 (assq (aref (symbol-name base) 0)
957 math-unit-prefixes))
958 expr)))
959 expr)
960 (if (eq base 'pi)
961 (math-pi)
962 expr)))
d6ffd3f8
JB
963 (if (or
964 (Math-primp expr)
965 (and (eq (car-safe expr) 'calcFunc-subscr)
966 (eq (car-safe (nth 1 expr)) 'var)))
136211a9
EZ
967 expr
968 (cons (car expr)
c9aef719 969 (mapcar 'math-to-standard-rec (cdr expr))))))
136211a9
EZ
970
971(defun math-apply-units (expr units ulist &optional pure)
2e2b4fbe 972 (setq expr (math-simplify-units expr))
136211a9
EZ
973 (if ulist
974 (let ((new 0)
975 value)
136211a9
EZ
976 (or (math-numberp expr)
977 (error "Incompatible units"))
978 (while (cdr ulist)
979 (setq value (math-div expr (nth 1 (car ulist)))
980 value (math-floor (let ((calc-internal-prec
981 (1- calc-internal-prec)))
982 (math-normalize value)))
983 new (math-add new (math-mul value (car (car ulist))))
984 expr (math-sub expr (math-mul value (nth 1 (car ulist))))
985 ulist (cdr ulist)))
986 (math-add new (math-mul (math-div expr (nth 1 (car ulist)))
987 (car (car ulist)))))
2e2b4fbe
JB
988 (if pure
989 expr
990 (math-simplify-units (list '* expr units)))))
136211a9 991
8cd8ee52 992(defvar math-decompose-units-cache nil)
136211a9
EZ
993(defun math-decompose-units (units)
994 (let ((u (math-check-unit-name units)))
995 (and u (eq (car-safe (nth 1 u)) '+)
996 (setq units (nth 1 u))))
997 (setq units (calcFunc-expand units))
998 (and (eq (car-safe units) '+)
999 (let ((entry (list units calc-internal-prec calc-prefer-frac)))
1000 (or (equal entry (car math-decompose-units-cache))
1001 (let ((ulist nil)
1002 (utemp units)
1003 qty unit)
1004 (while (eq (car-safe utemp) '+)
1005 (setq ulist (cons (math-decompose-unit-part (nth 2 utemp))
1006 ulist)
1007 utemp (nth 1 utemp)))
1008 (setq ulist (cons (math-decompose-unit-part utemp) ulist)
1009 utemp ulist)
1010 (while (setq utemp (cdr utemp))
8cd8ee52
CW
1011 (unless (equal (nth 2 (car utemp)) (nth 2 (car ulist)))
1012 (error "Inconsistent units in sum")))
136211a9
EZ
1013 (setq math-decompose-units-cache
1014 (cons entry
1015 (sort ulist
1016 (function
1017 (lambda (x y)
1018 (not (Math-lessp (nth 1 x)
1019 (nth 1 y))))))))))
c9aef719 1020 (cdr math-decompose-units-cache))))
136211a9
EZ
1021
1022(defun math-decompose-unit-part (unit)
1023 (cons unit
1024 (math-is-multiple (math-simplify-units (math-to-standard-units
1025 unit nil))
c9aef719 1026 t)))
136211a9 1027
27971241
JB
1028;; The variable math-fcu-u is local to math-find-compatible-unit,
1029;; but is used by math-find-compatible-rec which is called by
1030;; math-find-compatible-unit.
1031(defvar math-fcu-u)
1032
136211a9 1033(defun math-find-compatible-unit (expr unit)
27971241
JB
1034 (let ((math-fcu-u (math-check-unit-name unit)))
1035 (if math-fcu-u
c9aef719 1036 (math-find-compatible-unit-rec expr 1))))
136211a9
EZ
1037
1038(defun math-find-compatible-unit-rec (expr pow)
1039 (cond ((eq (car-safe expr) '*)
1040 (or (math-find-compatible-unit-rec (nth 1 expr) pow)
1041 (math-find-compatible-unit-rec (nth 2 expr) pow)))
1042 ((eq (car-safe expr) '/)
1043 (or (math-find-compatible-unit-rec (nth 1 expr) pow)
1044 (math-find-compatible-unit-rec (nth 2 expr) (- pow))))
1045 ((and (eq (car-safe expr) '^)
1046 (integerp (nth 2 expr)))
1047 (math-find-compatible-unit-rec (nth 1 expr) (* pow (nth 2 expr))))
1048 (t
1049 (let ((u2 (math-check-unit-name expr)))
27971241 1050 (if (equal (nth 4 math-fcu-u) (nth 4 u2))
c9aef719 1051 (cons expr pow))))))
136211a9 1052
09040c8d
JB
1053;; The variables math-cu-new-units and math-cu-pure are local to
1054;; math-convert-units, but are used by math-convert-units-rec,
27971241
JB
1055;; which is called by math-convert-units.
1056(defvar math-cu-new-units)
1057(defvar math-cu-pure)
1058
1059(defun math-convert-units (expr math-cu-new-units &optional math-cu-pure)
65b62d0a
JB
1060 (if (eq (car-safe math-cu-new-units) 'var)
1061 (let ((unew (assq (nth 1 math-cu-new-units)
1062 (math-build-units-table))))
1063 (if (eq (car-safe (nth 1 unew)) '+)
1064 (setq math-cu-new-units (nth 1 unew)))))
136211a9 1065 (math-with-extra-prec 2
09040c8d 1066 (let ((compat (and (not math-cu-pure)
27971241
JB
1067 (math-find-compatible-unit expr math-cu-new-units)))
1068 (math-cu-unit-list nil)
136211a9
EZ
1069 (math-combining-units nil))
1070 (if compat
1071 (math-simplify-units
1072 (math-mul (math-mul (math-simplify-units
1073 (math-div expr (math-pow (car compat)
1074 (cdr compat))))
27971241 1075 (math-pow math-cu-new-units (cdr compat)))
136211a9
EZ
1076 (math-simplify-units
1077 (math-to-standard-units
27971241 1078 (math-pow (math-div (car compat) math-cu-new-units)
136211a9
EZ
1079 (cdr compat))
1080 nil))))
27971241
JB
1081 (when (setq math-cu-unit-list (math-decompose-units math-cu-new-units))
1082 (setq math-cu-new-units (nth 2 (car math-cu-unit-list))))
8cd8ee52
CW
1083 (when (eq (car-safe expr) '+)
1084 (setq expr (math-simplify-units expr)))
136211a9
EZ
1085 (if (math-units-in-expr-p expr t)
1086 (math-convert-units-rec expr)
1087 (math-apply-units (math-to-standard-units
27971241
JB
1088 (list '/ expr math-cu-new-units) nil)
1089 math-cu-new-units math-cu-unit-list math-cu-pure))))))
136211a9
EZ
1090
1091(defun math-convert-units-rec (expr)
1092 (if (math-units-in-expr-p expr nil)
09040c8d 1093 (math-apply-units (math-to-standard-units
27971241
JB
1094 (list '/ expr math-cu-new-units) nil)
1095 math-cu-new-units math-cu-unit-list math-cu-pure)
136211a9
EZ
1096 (if (Math-primp expr)
1097 expr
1098 (cons (car expr)
c9aef719 1099 (mapcar 'math-convert-units-rec (cdr expr))))))
136211a9
EZ
1100
1101(defun math-convert-temperature (expr old new &optional pure)
1102 (let* ((units (math-single-units-in-expr-p expr))
1103 (uold (if old
1104 (if (or (null units)
1105 (equal (nth 1 old) (car units)))
1106 (math-check-unit-name old)
1107 (error "Inconsistent temperature units"))
1108 units))
1109 (unew (math-check-unit-name new)))
8cd8ee52
CW
1110 (unless (and (consp unew) (nth 3 unew))
1111 (error "Not a valid temperature unit"))
1112 (unless (and (consp uold) (nth 3 uold))
1113 (error "Not a pure temperature expression"))
136211a9
EZ
1114 (let ((v (car uold)))
1115 (setq expr (list '/ expr (list 'var v
1116 (intern (concat "var-"
1117 (symbol-name v)))))))
1118 (or (eq (nth 3 uold) (nth 3 unew))
1119 (cond ((eq (nth 3 uold) 'K)
e6cd99dc 1120 (setq expr (list '- expr '(/ 27315 100)))
136211a9 1121 (if (eq (nth 3 unew) 'F)
e6cd99dc 1122 (setq expr (list '+ (list '* expr '(/ 9 5)) 32))))
136211a9
EZ
1123 ((eq (nth 3 uold) 'C)
1124 (if (eq (nth 3 unew) 'F)
e6cd99dc
JB
1125 (setq expr (list '+ (list '* expr '(/ 9 5)) 32))
1126 (setq expr (list '+ expr '(/ 27315 100)))))
136211a9 1127 (t
e6cd99dc 1128 (setq expr (list '* (list '- expr 32) '(/ 5 9)))
136211a9 1129 (if (eq (nth 3 unew) 'K)
e6cd99dc 1130 (setq expr (list '+ expr '(/ 27315 100)))))))
136211a9
EZ
1131 (if pure
1132 expr
c9aef719 1133 (list '* expr new))))
136211a9
EZ
1134
1135
1136
1137(defun math-simplify-units (a)
1138 (let ((math-simplifying-units t)
1139 (calc-matrix-mode 'scalar))
c9aef719 1140 (math-simplify a)))
8cd8ee52 1141(defalias 'calcFunc-usimplify 'math-simplify-units)
136211a9 1142
f095c6c9
JB
1143;; The function created by math-defsimplify uses the variable
1144;; math-simplify-expr, and so is used by functions in math-defsimplify
1145(defvar math-simplify-expr)
1146
136211a9
EZ
1147(math-defsimplify (+ -)
1148 (and math-simplifying-units
f095c6c9
JB
1149 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
1150 (let* ((units (math-extract-units (nth 1 math-simplify-expr)))
136211a9 1151 (ratio (math-simplify (math-to-standard-units
f095c6c9 1152 (list '/ (nth 2 math-simplify-expr) units) nil))))
136211a9
EZ
1153 (if (math-units-in-expr-p ratio nil)
1154 (progn
f095c6c9
JB
1155 (calc-record-why "*Inconsistent units" math-simplify-expr)
1156 math-simplify-expr)
1157 (list '* (math-add (math-remove-units (nth 1 math-simplify-expr))
09040c8d 1158 (if (eq (car math-simplify-expr) '-)
f095c6c9 1159 (math-neg ratio) ratio))
c9aef719 1160 units)))))
136211a9
EZ
1161
1162(math-defsimplify *
c9aef719 1163 (math-simplify-units-prod))
136211a9
EZ
1164
1165(defun math-simplify-units-prod ()
1166 (and math-simplifying-units
1167 calc-autorange-units
f095c6c9
JB
1168 (Math-realp (nth 1 math-simplify-expr))
1169 (let* ((num (math-float (nth 1 math-simplify-expr)))
136211a9 1170 (xpon (calcFunc-xpon num))
f095c6c9 1171 (unitp (cdr (cdr math-simplify-expr)))
136211a9 1172 (unit (car unitp))
f095c6c9 1173 (pow (if (eq (car math-simplify-expr) '*) 1 -1))
136211a9
EZ
1174 u)
1175 (and (eq (car-safe unit) '*)
1176 (setq unitp (cdr unit)
1177 unit (car unitp)))
1178 (and (eq (car-safe unit) '^)
1179 (integerp (nth 2 unit))
1180 (setq pow (* pow (nth 2 unit))
1181 unitp (cdr unit)
1182 unit (car unitp)))
1183 (and (setq u (math-check-unit-name unit))
1184 (integerp xpon)
1185 (or (< xpon 0)
1186 (>= xpon (if (eq (car u) 'm) 1 3)))
1187 (let* ((uxpon 0)
1188 (pref (if (< pow 0)
1189 (reverse math-unit-prefixes)
1190 math-unit-prefixes))
1191 (p pref)
1192 pxpon pname)
1193 (or (eq (car u) (nth 1 unit))
1194 (setq uxpon (* pow
1195 (nth 2 (nth 1 (assq
1196 (aref (symbol-name
1197 (nth 1 unit)) 0)
1198 math-unit-prefixes))))))
1199 (setq xpon (+ xpon uxpon))
1200 (while (and p
1201 (or (memq (car (car p)) '(?d ?D ?h ?H))
1202 (and (eq (car (car p)) ?c)
1203 (not (eq (car u) 'm)))
1204 (< xpon (setq pxpon (* (nth 2 (nth 1 (car p)))
1205 pow)))
1206 (progn
1207 (setq pname (math-build-var-name
1208 (if (eq (car (car p)) 0)
1209 (car u)
1210 (concat (char-to-string
1211 (car (car p)))
1212 (symbol-name
1213 (car u))))))
1214 (and (/= (car (car p)) 0)
1215 (assq (nth 1 pname)
1216 math-units-table)))))
1217 (setq p (cdr p)))
1218 (and p
1219 (/= pxpon uxpon)
1220 (or (not (eq p pref))
1221 (< xpon (+ pxpon (* (math-abs pow) 3))))
1222 (progn
f095c6c9 1223 (setcar (cdr math-simplify-expr)
136211a9 1224 (let ((calc-prefer-frac nil))
f095c6c9 1225 (calcFunc-scf (nth 1 math-simplify-expr)
136211a9
EZ
1226 (- uxpon pxpon))))
1227 (setcar unitp pname)
f095c6c9 1228 math-simplify-expr)))))))
136211a9 1229
27971241
JB
1230(defvar math-try-cancel-units)
1231
136211a9
EZ
1232(math-defsimplify /
1233 (and math-simplifying-units
f095c6c9 1234 (let ((np (cdr math-simplify-expr))
27971241 1235 (math-try-cancel-units 0)
136211a9 1236 n nn)
f095c6c9
JB
1237 (setq n (if (eq (car-safe (nth 2 math-simplify-expr)) '*)
1238 (cdr (nth 2 math-simplify-expr))
1239 (nthcdr 2 math-simplify-expr)))
136211a9
EZ
1240 (if (math-realp (car n))
1241 (progn
f095c6c9 1242 (setcar (cdr math-simplify-expr) (math-mul (nth 1 math-simplify-expr)
136211a9
EZ
1243 (let ((calc-prefer-frac nil))
1244 (math-div 1 (car n)))))
1245 (setcar n 1)))
1246 (while (eq (car-safe (setq n (car np))) '*)
f095c6c9 1247 (math-simplify-units-divisor (cdr n) (cdr (cdr math-simplify-expr)))
136211a9 1248 (setq np (cdr (cdr n))))
f095c6c9 1249 (math-simplify-units-divisor np (cdr (cdr math-simplify-expr)))
27971241 1250 (if (eq math-try-cancel-units 0)
136211a9 1251 (let* ((math-simplifying-units nil)
09040c8d 1252 (base (math-simplify
f095c6c9 1253 (math-to-standard-units math-simplify-expr nil))))
136211a9 1254 (if (Math-numberp base)
f095c6c9
JB
1255 (setq math-simplify-expr base))))
1256 (if (eq (car-safe math-simplify-expr) '/)
136211a9 1257 (math-simplify-units-prod))
f095c6c9 1258 math-simplify-expr)))
136211a9
EZ
1259
1260(defun math-simplify-units-divisor (np dp)
1261 (let ((n (car np))
1262 d dd temp)
1263 (while (eq (car-safe (setq d (car dp))) '*)
8cd8ee52
CW
1264 (when (setq temp (math-simplify-units-quotient n (nth 1 d)))
1265 (setcar np (setq n temp))
1266 (setcar (cdr d) 1))
136211a9 1267 (setq dp (cdr (cdr d))))
8cd8ee52
CW
1268 (when (setq temp (math-simplify-units-quotient n d))
1269 (setcar np (setq n temp))
1270 (setcar dp 1))))
136211a9
EZ
1271
1272;; Simplify, e.g., "in / cm" to "2.54" in a units expression.
1273(defun math-simplify-units-quotient (n d)
1274 (let ((pow1 1)
1275 (pow2 1))
8cd8ee52
CW
1276 (when (and (eq (car-safe n) '^)
1277 (integerp (nth 2 n)))
1278 (setq pow1 (nth 2 n) n (nth 1 n)))
1279 (when (and (eq (car-safe d) '^)
1280 (integerp (nth 2 d)))
1281 (setq pow2 (nth 2 d) d (nth 1 d)))
136211a9
EZ
1282 (let ((un (math-check-unit-name n))
1283 (ud (math-check-unit-name d)))
1284 (and un ud
1285 (if (and (equal (nth 4 un) (nth 4 ud))
1286 (eq pow1 pow2))
0317ca78
JB
1287 (if (eq pow1 1)
1288 (math-to-standard-units (list '/ n d) nil)
1289 (list '^ (math-to-standard-units (list '/ n d) nil) pow1))
136211a9
EZ
1290 (let (ud1)
1291 (setq un (nth 4 un)
1292 ud (nth 4 ud))
1293 (while un
1294 (setq ud1 ud)
1295 (while ud1
1296 (and (eq (car (car un)) (car (car ud1)))
27971241
JB
1297 (setq math-try-cancel-units
1298 (+ math-try-cancel-units
136211a9
EZ
1299 (- (* (cdr (car un)) pow1)
1300 (* (cdr (car ud)) pow2)))))
1301 (setq ud1 (cdr ud1)))
1302 (setq un (cdr un)))
c9aef719 1303 nil))))))
136211a9
EZ
1304
1305(math-defsimplify ^
1306 (and math-simplifying-units
f095c6c9
JB
1307 (math-realp (nth 2 math-simplify-expr))
1308 (if (memq (car-safe (nth 1 math-simplify-expr)) '(* /))
1309 (list (car (nth 1 math-simplify-expr))
09040c8d 1310 (list '^ (nth 1 (nth 1 math-simplify-expr))
f095c6c9 1311 (nth 2 math-simplify-expr))
09040c8d 1312 (list '^ (nth 2 (nth 1 math-simplify-expr))
f095c6c9 1313 (nth 2 math-simplify-expr)))
09040c8d 1314 (math-simplify-units-pow (nth 1 math-simplify-expr)
f095c6c9 1315 (nth 2 math-simplify-expr)))))
136211a9
EZ
1316
1317(math-defsimplify calcFunc-sqrt
1318 (and math-simplifying-units
f095c6c9
JB
1319 (if (memq (car-safe (nth 1 math-simplify-expr)) '(* /))
1320 (list (car (nth 1 math-simplify-expr))
1321 (list 'calcFunc-sqrt (nth 1 (nth 1 math-simplify-expr)))
1322 (list 'calcFunc-sqrt (nth 2 (nth 1 math-simplify-expr))))
1323 (math-simplify-units-pow (nth 1 math-simplify-expr) '(frac 1 2)))))
136211a9
EZ
1324
1325(math-defsimplify (calcFunc-floor
1326 calcFunc-ceil
1327 calcFunc-round
1328 calcFunc-rounde
1329 calcFunc-roundu
1330 calcFunc-trunc
1331 calcFunc-float
1332 calcFunc-frac
1333 calcFunc-abs
1334 calcFunc-clean)
1335 (and math-simplifying-units
f095c6c9
JB
1336 (= (length math-simplify-expr) 2)
1337 (if (math-only-units-in-expr-p (nth 1 math-simplify-expr))
1338 (nth 1 math-simplify-expr)
1339 (if (and (memq (car-safe (nth 1 math-simplify-expr)) '(* /))
136211a9 1340 (or (math-only-units-in-expr-p
f095c6c9 1341 (nth 1 (nth 1 math-simplify-expr)))
136211a9 1342 (math-only-units-in-expr-p
f095c6c9
JB
1343 (nth 2 (nth 1 math-simplify-expr)))))
1344 (list (car (nth 1 math-simplify-expr))
1345 (cons (car math-simplify-expr)
1346 (cons (nth 1 (nth 1 math-simplify-expr))
1347 (cdr (cdr math-simplify-expr))))
1348 (cons (car math-simplify-expr)
1349 (cons (nth 2 (nth 1 math-simplify-expr))
1350 (cdr (cdr math-simplify-expr)))))))))
136211a9
EZ
1351
1352(defun math-simplify-units-pow (a pow)
1353 (if (and (eq (car-safe a) '^)
1354 (math-check-unit-name (nth 1 a))
1355 (math-realp (nth 2 a)))
1356 (list '^ (nth 1 a) (math-mul pow (nth 2 a)))
1357 (let* ((u (math-check-unit-name a))
1358 (pf (math-to-simple-fraction pow))
1359 (d (and (eq (car-safe pf) 'frac) (nth 2 pf))))
1360 (and u d
1361 (math-units-are-multiple u d)
c9aef719 1362 (list '^ (math-to-standard-units a nil) pow)))))
136211a9
EZ
1363
1364
1365(defun math-units-are-multiple (u n)
1366 (setq u (nth 4 u))
1367 (while (and u (= (% (cdr (car u)) n) 0))
1368 (setq u (cdr u)))
c9aef719 1369 (null u))
136211a9
EZ
1370
1371(math-defsimplify calcFunc-sin
1372 (and math-simplifying-units
f095c6c9 1373 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
136211a9
EZ
1374 (let ((rad (math-simplify-units
1375 (math-evaluate-expr
f095c6c9 1376 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
136211a9
EZ
1377 (calc-angle-mode 'rad))
1378 (and (eq (car-safe rad) '*)
1379 (math-realp (nth 1 rad))
1380 (eq (car-safe (nth 2 rad)) 'var)
1381 (eq (nth 1 (nth 2 rad)) 'rad)
c9aef719 1382 (list 'calcFunc-sin (nth 1 rad))))))
136211a9
EZ
1383
1384(math-defsimplify calcFunc-cos
1385 (and math-simplifying-units
f095c6c9 1386 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
136211a9
EZ
1387 (let ((rad (math-simplify-units
1388 (math-evaluate-expr
f095c6c9 1389 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
136211a9
EZ
1390 (calc-angle-mode 'rad))
1391 (and (eq (car-safe rad) '*)
1392 (math-realp (nth 1 rad))
1393 (eq (car-safe (nth 2 rad)) 'var)
1394 (eq (nth 1 (nth 2 rad)) 'rad)
c9aef719 1395 (list 'calcFunc-cos (nth 1 rad))))))
136211a9
EZ
1396
1397(math-defsimplify calcFunc-tan
1398 (and math-simplifying-units
f095c6c9 1399 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
136211a9
EZ
1400 (let ((rad (math-simplify-units
1401 (math-evaluate-expr
f095c6c9 1402 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
136211a9
EZ
1403 (calc-angle-mode 'rad))
1404 (and (eq (car-safe rad) '*)
1405 (math-realp (nth 1 rad))
1406 (eq (car-safe (nth 2 rad)) 'var)
1407 (eq (nth 1 (nth 2 rad)) 'rad)
c9aef719 1408 (list 'calcFunc-tan (nth 1 rad))))))
136211a9 1409
40b444ac
JB
1410(math-defsimplify calcFunc-sec
1411 (and math-simplifying-units
1412 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
1413 (let ((rad (math-simplify-units
1414 (math-evaluate-expr
1415 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
1416 (calc-angle-mode 'rad))
1417 (and (eq (car-safe rad) '*)
1418 (math-realp (nth 1 rad))
1419 (eq (car-safe (nth 2 rad)) 'var)
1420 (eq (nth 1 (nth 2 rad)) 'rad)
1421 (list 'calcFunc-sec (nth 1 rad))))))
1422
1423(math-defsimplify calcFunc-csc
1424 (and math-simplifying-units
1425 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
1426 (let ((rad (math-simplify-units
1427 (math-evaluate-expr
1428 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
1429 (calc-angle-mode 'rad))
1430 (and (eq (car-safe rad) '*)
1431 (math-realp (nth 1 rad))
1432 (eq (car-safe (nth 2 rad)) 'var)
1433 (eq (nth 1 (nth 2 rad)) 'rad)
1434 (list 'calcFunc-csc (nth 1 rad))))))
1435
1436(math-defsimplify calcFunc-cot
1437 (and math-simplifying-units
1438 (math-units-in-expr-p (nth 1 math-simplify-expr) nil)
1439 (let ((rad (math-simplify-units
1440 (math-evaluate-expr
1441 (math-to-standard-units (nth 1 math-simplify-expr) nil))))
1442 (calc-angle-mode 'rad))
1443 (and (eq (car-safe rad) '*)
1444 (math-realp (nth 1 rad))
1445 (eq (car-safe (nth 2 rad)) 'var)
1446 (eq (nth 1 (nth 2 rad)) 'rad)
1447 (list 'calcFunc-cot (nth 1 rad))))))
1448
136211a9
EZ
1449
1450(defun math-remove-units (expr)
1451 (if (math-check-unit-name expr)
1452 1
1453 (if (Math-primp expr)
1454 expr
1455 (cons (car expr)
c9aef719 1456 (mapcar 'math-remove-units (cdr expr))))))
136211a9
EZ
1457
1458(defun math-extract-units (expr)
1459 (if (memq (car-safe expr) '(* /))
1460 (cons (car expr)
1461 (mapcar 'math-extract-units (cdr expr)))
c9aef719 1462 (if (math-check-unit-name expr) expr 1)))
136211a9
EZ
1463
1464(defun math-build-units-table-buffer (enter-buffer)
1465 (if (not (and math-units-table math-units-table-buffer-valid
1466 (get-buffer "*Units Table*")))
1467 (let ((buf (get-buffer-create "*Units Table*"))
1468 (uptr (math-build-units-table))
1469 (calc-language (if (eq calc-language 'big) nil calc-language))
1470 (calc-float-format '(float 0))
1471 (calc-group-digits nil)
1472 (calc-number-radix 10)
7b999abb 1473 (calc-twos-complement-mode nil)
136211a9
EZ
1474 (calc-point-char ".")
1475 (std nil)
1476 u name shadowed)
1477 (save-excursion
1478 (message "Formatting units table...")
1479 (set-buffer buf)
ed8060d9
JB
1480 (let ((inhibit-read-only t))
1481 (erase-buffer)
1482 (insert "Calculator Units Table:\n\n")
ac318df0 1483 (insert "(All definitions are exact unless marked with an asterisk (*).)\n\n")
ed8060d9
JB
1484 (insert "Unit Type Definition Description\n\n")
1485 (while uptr
1486 (setq u (car uptr)
1487 name (nth 2 u))
1488 (when (eq (car u) 'm)
1489 (setq std t))
1490 (setq shadowed (and std (assq (car u) math-additional-units)))
1491 (when (and name
1492 (> (length name) 1)
1493 (eq (aref name 0) ?\*))
1494 (unless (eq uptr math-units-table)
1495 (insert "\n"))
1496 (setq name (substring name 1)))
1497 (insert " ")
1498 (and shadowed (insert "("))
1499 (insert (symbol-name (car u)))
1500 (and shadowed (insert ")"))
1501 (if (nth 3 u)
1502 (progn
1503 (indent-to 10)
1504 (insert (symbol-name (nth 3 u))))
1505 (or std
1506 (progn
1507 (indent-to 10)
1508 (insert "U"))))
1509 (indent-to 14)
1510 (and shadowed (insert "("))
19bdc4d8
JB
1511 (if (nth 5 u)
1512 (insert (nth 5 u))
1513 (if (nth 1 u)
1514 (insert (math-format-value (nth 1 u) 80))
1515 (insert (symbol-name (car u)))))
ed8060d9
JB
1516 (and shadowed (insert ")"))
1517 (indent-to 41)
1518 (insert " ")
1519 (when name
1520 (insert name))
1521 (if shadowed
1522 (insert " (redefined above)")
1523 (unless (nth 1 u)
1524 (insert " (base unit)")))
1525 (insert "\n")
1526 (setq uptr (cdr uptr)))
1527 (insert "\n\nUnit Prefix Table:\n\n")
1528 (setq uptr math-unit-prefixes)
1529 (while uptr
1530 (setq u (car uptr))
1531 (insert " " (char-to-string (car u)))
1532 (if (equal (nth 1 u) (nth 1 (nth 1 uptr)))
1533 (insert " " (char-to-string (car (car (setq uptr (cdr uptr)))))
1534 " ")
1535 (insert " "))
1536 (insert "10^" (int-to-string (nth 2 (nth 1 u))))
1537 (indent-to 15)
1538 (insert " " (nth 2 u) "\n")
1539 (while (eq (car (car (setq uptr (cdr uptr)))) 0)))
1265829e
JB
1540 (insert "\n\n")
1541 (insert "(**) When in TeX or LaTeX display mode, the TeX specific unit\n"
1542 "names will not use the `tex' prefix; the unit name for a\n"
1543 "TeX point will be `pt' instead of `texpt', for example.\n"
1544 "To avoid conflicts, the unit names for pint and parsec will\n"
1545 "be `pint' and `parsec' instead of `pt' and `pc'."))
ed8060d9 1546 (view-mode)
136211a9
EZ
1547 (message "Formatting units table...done"))
1548 (setq math-units-table-buffer-valid t)
1549 (let ((oldbuf (current-buffer)))
1550 (set-buffer buf)
1551 (goto-char (point-min))
1552 (set-buffer oldbuf))
1553 (if enter-buffer
1554 (pop-to-buffer buf)
1555 (display-buffer buf)))
1556 (if enter-buffer
1557 (pop-to-buffer (get-buffer "*Units Table*"))
c9aef719 1558 (display-buffer (get-buffer "*Units Table*")))))
136211a9 1559
603823f5
JB
1560;;; Logarithmic units functions
1561
1562(defvar math-logunits '((var dB var-dB)
1563 (var Np var-Np)))
1564
771fc75e
JB
1565(defun math-conditional-apply (fn &rest args)
1566 "Evaluate f(args) unless in symbolic mode.
1567In symbolic mode, return the list (fn args)."
1568 (if calc-symbolic-mode
1569 (cons fn args)
1570 (apply fn args)))
1571
1572(defun math-conditional-pow (a b)
1573 "Evaluate a^b unless in symbolic mode.
1574In symbolic mode, return the list (^ a b)."
1575 (if calc-symbolic-mode
1576 (list '^ a b)
1577 (math-pow a b)))
1578
603823f5
JB
1579(defun math-extract-logunits (expr)
1580 (if (memq (car-safe expr) '(* /))
1581 (cons (car expr)
1582 (mapcar 'math-extract-logunits (cdr expr)))
1583 (if (memq (car-safe expr) '(^))
1584 (list '^ (math-extract-logunits (nth 1 expr)) (nth 2 expr))
1585 (if (member expr math-logunits) expr 1))))
1586
ec6ad6f2 1587(defun math-logunits-add (a b neg power)
603823f5
JB
1588 (let ((aunit (math-simplify (math-extract-logunits a))))
1589 (if (not (eq (car-safe aunit) 'var))
1590 (calc-record-why "*Improper logarithmic unit" aunit)
1591 (let* ((units (math-extract-units a))
1592 (acoeff (math-simplify (math-remove-units a)))
1593 (bcoeff (math-simplify (math-to-standard-units
1594 (list '/ b units) nil))))
1595 (if (math-units-in-expr-p bcoeff nil)
1596 (calc-record-why "*Inconsistent units" nil)
1597 (if (and neg
1598 (or (math-lessp acoeff bcoeff)
1599 (math-equal acoeff bcoeff)))
1600 (calc-record-why "*Improper coefficients" nil)
1601 (math-mul
1602 (if (equal aunit '(var dB var-dB))
6f16becc
JB
1603 (let ((coef (if power 10 20)))
1604 (math-mul coef
771fc75e 1605 (math-conditional-apply 'calcFunc-log10
6f16becc
JB
1606 (if neg
1607 (math-sub
771fc75e
JB
1608 (math-conditional-pow 10 (math-div acoeff coef))
1609 (math-conditional-pow 10 (math-div bcoeff coef)))
6f16becc 1610 (math-add
771fc75e
JB
1611 (math-conditional-pow 10 (math-div acoeff coef))
1612 (math-conditional-pow 10 (math-div bcoeff coef)))))))
6f16becc
JB
1613 (let ((coef (if power 2 1)))
1614 (math-div
771fc75e 1615 (math-conditional-apply 'calcFunc-ln
6f16becc
JB
1616 (if neg
1617 (math-sub
771fc75e
JB
1618 (math-conditional-apply 'calcFunc-exp (math-mul coef acoeff))
1619 (math-conditional-apply 'calcFunc-exp (math-mul coef bcoeff)))
6f16becc 1620 (math-add
771fc75e
JB
1621 (math-conditional-apply 'calcFunc-exp (math-mul coef acoeff))
1622 (math-conditional-apply 'calcFunc-exp (math-mul coef bcoeff)))))
6f16becc 1623 coef)))
603823f5
JB
1624 units)))))))
1625
6f16becc 1626(defun calcFunc-lufieldplus (a b)
ec6ad6f2 1627 (math-logunits-add a b nil nil))
603823f5 1628
6f16becc 1629(defun calcFunc-lupowerplus (a b)
ec6ad6f2 1630 (math-logunits-add a b nil t))
603823f5 1631
6f16becc 1632(defun calcFunc-lufieldminus (a b)
ec6ad6f2 1633 (math-logunits-add a b t nil))
6f16becc
JB
1634
1635(defun calcFunc-lupowerminus (a b)
ec6ad6f2 1636 (math-logunits-add a b t t))
6f16becc 1637
ec6ad6f2 1638(defun calc-logunits-add (arg)
603823f5
JB
1639 (interactive "P")
1640 (calc-slow-wrapper
1641 (if (calc-is-inverse)
6f16becc
JB
1642 (if (calc-is-hyperbolic)
1643 (calc-binary-op "lu-" 'calcFunc-lufieldminus arg)
1644 (calc-binary-op "lu-" 'calcFunc-lupowerminus arg))
1645 (if (calc-is-hyperbolic)
1646 (calc-binary-op "lu+" 'calcFunc-lufieldplus arg)
1647 (calc-binary-op "lu+" 'calcFunc-lupowerplus arg)))))
1648
ec6ad6f2 1649(defun calc-logunits-sub (arg)
6f16becc
JB
1650 (interactive "P")
1651 (calc-slow-wrapper
1652 (if (calc-is-inverse)
1653 (if (calc-is-hyperbolic)
1654 (calc-binary-op "lu+" 'calcFunc-lufieldplus arg)
1655 (calc-binary-op "lu+" 'calcFunc-lupowerplus arg))
1656 (if (calc-is-hyperbolic)
1657 (calc-binary-op "lu-" 'calcFunc-lufieldminus arg)
1658 (calc-binary-op "lu-" 'calcFunc-lupowerminus arg)))))
1659
ec6ad6f2 1660(defun math-logunits-mul (a b power)
6f16becc
JB
1661 (let (logunit coef units number)
1662 (cond
1663 ((and
1664 (setq logunit (math-simplify (math-extract-logunits a)))
1665 (eq (car-safe logunit) 'var)
1666 (eq (math-simplify (math-extract-units b)) 1))
1667 (setq coef (math-simplify (math-remove-units a))
1668 units (math-extract-units a)
1669 number b))
1670 ((and
1671 (setq logunit (math-simplify (math-extract-logunits b)))
1672 (eq (car-safe logunit) 'var)
1673 (eq (math-simplify (math-extract-units a)) 1))
1674 (setq coef (math-simplify (math-remove-units b))
1675 units (math-extract-units b)
1676 number a))
1677 (t (setq logunit nil)))
1678 (if logunit
1679 (cond
1680 ((equal logunit '(var dB var-dB))
1681 (math-simplify
1682 (math-mul
1683 (math-add
1684 coef
1685 (math-mul (if power 10 20)
771fc75e 1686 (math-conditional-apply 'calcFunc-log10 number)))
6f16becc
JB
1687 units)))
1688 (t
1689 (math-simplify
1690 (math-mul
1691 (math-add
1692 coef
771fc75e 1693 (math-div (math-conditional-apply 'calcFunc-ln number) (if power 2 1)))
6f16becc
JB
1694 units))))
1695 (calc-record-why "*Improper units" nil))))
1696
1697(defun math-logunits-divide (a b power)
1698 (let ((logunit (math-simplify (math-extract-logunits a))))
1699 (if (not (eq (car-safe logunit) 'var))
1700 (calc-record-why "*Improper logarithmic unit" logunit)
1701 (if (math-units-in-expr-p b nil)
1702 (calc-record-why "*Improper units quantity" b)
1703 (let* ((units (math-extract-units a))
1704 (coef (math-simplify (math-remove-units a))))
1705 (cond
1706 ((equal logunit '(var dB var-dB))
1707 (math-simplify
1708 (math-mul
1709 (math-sub
1710 coef
1711 (math-mul (if power 10 20)
771fc75e 1712 (math-conditional-apply 'calcFunc-log10 b)))
6f16becc
JB
1713 units)))
1714 (t
1715 (math-simplify
1716 (math-mul
1717 (math-sub
1718 coef
771fc75e 1719 (math-div (math-conditional-apply 'calcFunc-ln b) (if power 2 1)))
6f16becc
JB
1720 units)))))))))
1721
1722(defun calcFunc-lufieldtimes (a b)
ec6ad6f2 1723 (math-logunits-mul a b nil))
6f16becc
JB
1724
1725(defun calcFunc-lupowertimes (a b)
ec6ad6f2 1726 (math-logunits-mul a b t))
6f16becc 1727
ec6ad6f2 1728(defun calc-logunits-mul (arg)
603823f5
JB
1729 (interactive "P")
1730 (calc-slow-wrapper
1731 (if (calc-is-inverse)
6f16becc
JB
1732 (if (calc-is-hyperbolic)
1733 (calc-binary-op "lu/" 'calcFunc-lufielddiv arg)
1734 (calc-binary-op "lu/" 'calcFunc-lupowerdiv arg))
1735 (if (calc-is-hyperbolic)
1736 (calc-binary-op "lu*" 'calcFunc-lufieldtimes arg)
1737 (calc-binary-op "lu*" 'calcFunc-lupowertimes arg)))))
603823f5 1738
6f16becc
JB
1739(defun calcFunc-lufielddiv (a b)
1740 (math-logunits-divide a b nil))
603823f5 1741
6f16becc
JB
1742(defun calcFunc-lupowerdiv (a b)
1743 (math-logunits-divide a b t))
603823f5 1744
6f16becc
JB
1745(defun calc-logunits-divide (arg)
1746 (interactive "P")
1747 (calc-slow-wrapper
1748 (if (calc-is-inverse)
1749 (if (calc-is-hyperbolic)
1750 (calc-binary-op "lu*" 'calcFunc-lufieldtimes arg)
1751 (calc-binary-op "lu*" 'calcFunc-lupowertimes arg))
1752 (if (calc-is-hyperbolic)
1753 (calc-binary-op "lu/" 'calcFunc-lufielddiv arg)
1754 (calc-binary-op "lu/" 'calcFunc-lupowerdiv arg)))))
1755
1756(defun math-logunits-quant (val ref power)
226590f8
JB
1757 (let* ((units (math-simplify (math-extract-units val)))
1758 (lunit (math-simplify (math-extract-logunits units))))
603823f5
JB
1759 (if (not (eq (car-safe lunit) 'var))
1760 (calc-record-why "*Improper logarithmic unit" lunit)
226590f8
JB
1761 (let ((runits (math-simplify (math-div units lunit)))
1762 (coeff (math-simplify (math-div val units))))
1763 (math-mul
1764 (if (equal lunit '(var dB var-dB))
1765 (math-mul
1766 ref
771fc75e 1767 (math-conditional-pow
226590f8
JB
1768 10
1769 (math-div
1770 coeff
1771 (if power 10 20))))
1772 (math-mul
1773 ref
771fc75e 1774 (math-conditional-apply 'calcFunc-exp
226590f8
JB
1775 (if power
1776 (math-mul 2 coeff)
1777 coeff))))
1778 runits)))))
603823f5 1779
6f16becc
JB
1780(defvar calc-logunits-field-reference)
1781(defvar calc-logunits-power-reference)
603823f5 1782
6f16becc 1783(defun calcFunc-fieldquant (val &optional ref)
603823f5 1784 (unless ref
6f16becc
JB
1785 (setq ref (math-read-expr calc-logunits-field-reference)))
1786 (math-logunits-quant val ref nil))
603823f5 1787
6f16becc 1788(defun calcFunc-powerquant (val &optional ref)
603823f5 1789 (unless ref
6f16becc
JB
1790 (setq ref (math-read-expr calc-logunits-power-reference)))
1791 (math-logunits-quant val ref t))
1792
1793(defun calc-logunits-quantity (arg)
1794 (interactive "P")
1795 (calc-slow-wrapper
1796 (if (calc-is-hyperbolic)
1797 (if (calc-is-option)
1798 (calc-binary-op "lupq" 'calcFunc-fieldquant arg)
1799 (calc-unary-op "lupq" 'calcFunc-fieldquant arg))
1800 (if (calc-is-option)
1801 (calc-binary-op "lufq" 'calcFunc-powerquant arg)
1802 (calc-unary-op "lufq" 'calcFunc-powerquant arg)))))
1803
1804(defun math-logunits-level (val ref db power)
1805 "Compute the value of VAL in decibels or nepers."
1806 (let* ((ratio (math-simplify-units (math-div val ref)))
771fc75e 1807 (ratiou (math-simplify-units (math-remove-units ratio)))
6f16becc
JB
1808 (units (math-simplify (math-extract-units ratio))))
1809 (math-mul
1810 (if db
1811 (math-mul
1812 (math-mul (if power 10 20)
771fc75e 1813 (math-conditional-apply 'calcFunc-log10 ratiou))
6f16becc
JB
1814 '(var dB var-dB))
1815 (math-mul
771fc75e 1816 (math-div (math-conditional-apply 'calcFunc-ln ratiou) (if power 2 1))
6f16becc
JB
1817 '(var Np var-Np)))
1818 units)))
1819
1820(defun calcFunc-dbfieldlevel (val &optional ref)
1821 (unless ref
1822 (setq ref (math-read-expr calc-logunits-field-reference)))
1823 (math-logunits-level val ref t nil))
1824
1825(defun calcFunc-dbpowerlevel (val &optional ref)
1826 (unless ref
1827 (setq ref (math-read-expr calc-logunits-power-reference)))
1828 (math-logunits-level val ref t t))
1829
1830(defun calcFunc-npfieldlevel (val &optional ref)
1831 (unless ref
1832 (setq ref (math-read-expr calc-logunits-field-reference)))
1833 (math-logunits-level val ref nil nil))
1834
1835(defun calcFunc-nppowerlevel (val &optional ref)
1836 (unless ref
1837 (setq ref (math-read-expr calc-logunits-power-reference)))
1838 (math-logunits-level val ref nil t))
1839
479a2c9b 1840(defun calc-dblevel (arg)
6f16becc
JB
1841 (interactive "P")
1842 (calc-slow-wrapper
1843 (if (calc-is-hyperbolic)
1844 (if (calc-is-option)
1845 (calc-binary-op "ludb" 'calcFunc-dbfieldlevel arg)
1846 (calc-unary-op "ludb" 'calcFunc-dbfieldlevel arg))
1847 (if (calc-is-option)
1848 (calc-binary-op "ludb" 'calcFunc-dbpowerlevel arg)
1849 (calc-unary-op "ludb" 'calcFunc-dbpowerlevel arg)))))
603823f5 1850
479a2c9b 1851(defun calc-nplevel (arg)
603823f5
JB
1852 (interactive "P")
1853 (calc-slow-wrapper
1854 (if (calc-is-hyperbolic)
1855 (if (calc-is-option)
6f16becc
JB
1856 (calc-binary-op "lunp" 'calcFunc-npfieldlevel arg)
1857 (calc-unary-op "lunp" 'calcFunc-npfieldlevel arg))
603823f5 1858 (if (calc-is-option)
6f16becc
JB
1859 (calc-binary-op "lunp" 'calcFunc-nppowerlevel arg)
1860 (calc-unary-op "lunp" 'calcFunc-nppowerlevel arg)))))
603823f5 1861
05a29101
JB
1862;;; Musical notes
1863
1864
1865(defvar calc-note-threshold)
1866
1867(defun math-midi-round (num)
1868 "Round NUM to an integer N if NUM is within calc-note-threshold cents of N."
1869 (let* ((n (math-round num))
1870 (diff (math-abs
1871 (math-sub num n))))
1872 (if (< (math-compare diff (math-read-expr calc-note-threshold)) 0)
1873 n
1874 num)))
1875
1876(defconst math-notes
1877 '(((var C var-C) . 0)
1878 ((var Csharp var-Csharp) . 1)
1879; ((var C♯ var-C♯) . 1)
1880 ((var Dflat var-Dflat) . 1)
1881; ((var D♭ var-D♭) . 1)
1882 ((var D var-D) . 2)
1883 ((var Dsharp var-Dsharp) . 3)
1884; ((var D♯ var-D♯) . 3)
1885 ((var E var-E) . 4)
1886 ((var F var-F) . 5)
1887 ((var Fsharp var-Fsharp) . 6)
1888; ((var F♯ var-F♯) . 6)
1889 ((var Gflat var-Gflat) . 6)
1890; ((var G♭ var-G♭) . 6)
1891 ((var G var-G) . 7)
1892 ((var Gsharp var-Gsharp) . 8)
1893; ((var G♯ var-G♯) . 8)
1894 ((var A var-A) . 9)
1895 ((var Asharp var-Asharp) . 10)
1896; ((var A♯ var-A♯) . 10)
1897 ((var Bflat var-Bflat) . 10)
1898; ((var B♭ var-B♭) . 10)
1899 ((var B var-B) . 11))
1900 "An alist of notes with their number of semitones above C.")
1901
1902(defun math-freqp (freq)
1903 "Non-nil if FREQ is a positive number times the unit Hz.
1904If non-nil, return the coefficient of Hz."
1905 (let ((freqcoef (math-simplify-units
1906 (math-div freq '(var Hz var-Hz)))))
1907 (if (Math-posp freqcoef) freqcoef)))
1908
1909(defun math-midip (num)
1910 "Non-nil if NUM is a possible MIDI note number.
1911If non-nil, return NUM."
1912 (if (Math-numberp num) num))
1913
1914(defun math-spnp (spn)
1915 "Non-nil if NUM is a scientific pitch note (note + cents).
1916If non-nil, return a list consisting of the note and the cents coefficient."
1917 (let (note cents rnote rcents)
1918 (if (eq (car-safe spn) '+)
1919 (setq note (nth 1 spn)
1920 cents (nth 2 spn))
1921 (setq note spn
1922 cents nil))
1923 (cond
1924 ((and ;; NOTE is a note, CENTS is nil or cents.
1925 (eq (car-safe note) 'calcFunc-subscr)
1926 (assoc (nth 1 note) math-notes)
1927 (integerp (nth 2 note))
1928 (setq rnote note)
1929 (or
1930 (not cents)
1931 (Math-numberp (setq rcents
1932 (math-simplify
1933 (math-div cents '(var cents var-cents)))))))
1934 (list rnote rcents))
1935 ((and ;; CENTS is a note, NOTE is cents.
1936 (eq (car-safe cents) 'calcFunc-subscr)
1937 (assoc (nth 1 cents) math-notes)
1938 (integerp (nth 2 cents))
1939 (setq rnote cents)
1940 (or
1941 (not note)
1942 (Math-numberp (setq rcents
1943 (math-simplify
1944 (math-div note '(var cents var-cents)))))))
1945 (list rnote rcents)))))
1946
1947(defun math-freq-to-midi (freq)
1948 "Return the midi note number corresponding to FREQ Hz."
1949 (let ((midi (math-add
1950 69
1951 (math-mul
1952 12
1953 (calcFunc-log
1954 (math-div freq 440)
1955 2)))))
1956 (math-midi-round midi)))
1957
1958(defun math-spn-to-midi (spn)
1959 "Return the MIDI number corresponding to SPN."
1960 (let* ((note (cdr (assoc (nth 1 (car spn)) math-notes)))
1961 (octave (math-add (nth 2 (car spn)) 1))
1962 (cents (nth 1 spn))
1963 (midi (math-add
1964 (math-mul 12 octave)
1965 note)))
1966 (if cents
1967 (math-add midi (math-div cents 100))
1968 midi)))
1969
1970(defun math-midi-to-spn (midi)
1971 "Return the scientific pitch notation corresponding to midi number MIDI."
1972 (let (midin cents)
1973 (if (math-integerp midi)
1974 (setq midin midi
1975 cents nil)
1976 (setq midin (math-floor midi)
1977 cents (math-mul 100 (math-sub midi midin))))
1978 (let* ((nr ;; This should be (math-idivmod midin 12), but with
1979 ;; better behavior for negative midin.
1980 (if (Math-negp midin)
1981 (let ((dm (math-idivmod (math-neg midin) 12)))
1982 (if (= (cdr dm) 0)
1983 (cons (math-neg (car dm)) 0)
1984 (cons
1985 (math-sub (math-neg (car dm)) 1)
1986 (math-sub 12 (cdr dm)))))
1987 (math-idivmod midin 12)))
1988 (n (math-sub (car nr) 1))
1989 (note (car (rassoc (cdr nr) math-notes))))
1990 (if cents
1991 (list '+ (list 'calcFunc-subscr note n)
1992 (list '* cents '(var cents var-cents)))
1993 (list 'calcFunc-subscr note n)))))
1994
1995(defun math-freq-to-spn (freq)
1996 "Return the scientific pitch notation corresponding to FREQ Hz."
1997 (math-with-extra-prec 3
1998 (math-midi-to-spn (math-freq-to-midi freq))))
1999
2000(defun math-midi-to-freq (midi)
2001 "Return the frequency of the note with midi number MIDI."
2002 (list '*
2003 (math-mul
2004 440
2005 (math-pow
2006 2
2007 (math-div
2008 (math-sub
2009 midi
2010 69)
2011 12)))
2012 '(var Hz var-Hz)))
2013
2014(defun math-spn-to-freq (spn)
2015 "Return the frequency of the note with scientific pitch notation SPN."
2016 (math-midi-to-freq (math-spn-to-midi spn)))
2017
2018(defun calcFunc-spn (expr)
2019 "Return EXPR written as scientific pitch notation + cents."
2020 ;; Get the coeffecient of Hz
2021 (let (note)
2022 (cond
2023 ((setq note (math-freqp expr))
2024 (math-freq-to-spn note))
2025 ((setq note (math-midip expr))
2026 (math-midi-to-spn note))
2027 ((math-spnp expr)
2028 expr)
2029 (t
2030 (math-reject-arg expr "*Improper expression")))))
2031
2032(defun calcFunc-midi (expr)
2033 "Return EXPR written as a MIDI number."
2034 (let (note)
2035 (cond
2036 ((setq note (math-freqp expr))
2037 (math-freq-to-midi note))
2038 ((setq note (math-spnp expr))
2039 (math-spn-to-midi note))
2040 ((math-midip expr)
2041 expr)
2042 (t
2043 (math-reject-arg expr "*Improper expression")))))
2044
2045(defun calcFunc-freq (expr)
2046 "Return the frequency corresponding to EXPR."
2047 (let (note)
2048 (cond
2049 ((setq note (math-midip expr))
2050 (math-midi-to-freq note))
2051 ((setq note (math-spnp expr))
2052 (math-spn-to-freq note))
2053 ((math-freqp expr)
2054 expr)
2055 (t
2056 (math-reject-arg expr "*Improper expression")))))
2057
2058(defun calc-freq (arg)
2059 "Return the frequency corresponding to the expression on the stack."
2060 (interactive "P")
2061 (calc-slow-wrapper
2062 (calc-unary-op "freq" 'calcFunc-freq arg)))
2063
2064(defun calc-midi (arg)
2065 "Return the MIDI number corresponding to the expression on the stack."
2066 (interactive "P")
2067 (calc-slow-wrapper
2068 (calc-unary-op "midi" 'calcFunc-midi arg)))
2069
2070(defun calc-spn (arg)
2071 "Return the scientific pitch notation corresponding to the expression on the stack."
2072 (interactive "P")
2073 (calc-slow-wrapper
2074 (calc-unary-op "spn" 'calcFunc-spn arg)))
2075
2076
7d02e8cd
JB
2077(provide 'calc-units)
2078
be19ef0b
GM
2079;; Local variables:
2080;; coding: utf-8
2081;; End:
2082
c9aef719 2083;;; calc-units.el ends here