calc-units.el 72 KB

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