* calc/calc-math.el (calcFunc-log10): Check for symbolic mode
[bpt/emacs.git] / lisp / calc / calc-units.el
index 20ccb92..e6a6fb0 100644 (file)
@@ -1,7 +1,6 @@
 ;;; calc-units.el --- unit conversion functions for Calc
 
-;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 1990-1993, 2001-2011  Free Software Foundation, Inc.
 
 ;; Author: David Gillespie <daveg@synaptics.com>
 ;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
 
 ;;; Units table last updated 9-Jan-91 by Ulrich Mueller (ulm@vsnhd1.cern.ch)
 ;;; with some additions by Przemek Klosowski (przemek@rrdstrad.nist.gov)
-;;; Updated April 2002 by Jochen Küpper
+;;; Updated April 2002 by Jochen Küpper
 
 ;;; Updated August 2007, using
 ;;;     CODATA (http://physics.nist.gov/cuu/Constants/index.html)
 ;;;     NIST   (http://physics.nist.gov/Pubs/SP811/appenB9.html)
 ;;;     ESUWM  (Encyclopaedia of Scientific Units, Weights and
-;;;             Measures, by François Cardarelli)
+;;;             Measures, by François Cardarelli)
 ;;; All conversions are exact unless otherwise noted.
 
 (defvar math-standard-units
   '( ;; Length
     ( m       nil                    "*Meter" )
-    ( in      "254*10^(-2) cm"       "Inch"  nil 
+    ( in      "254*10^(-2) cm"       "Inch"  nil
               "2.54 cm")
     ( ft      "12 in"                "Foot")
     ( yd      "3 ft"                 "Yard" )
     ( mi      "5280 ft"              "Mile" )
-    ( au      "149597870691. m"      "Astronomical Unit" nil 
+    ( au      "149597870691. m"      "Astronomical Unit" nil
               "149597870691 m (*)")
               ;; (approx) NASA JPL (http://neo.jpl.nasa.gov/glossary/au.html)
     ( lyr     "c yr"                 "Light Year" )
-    ( pc      "3.0856775854*10^16 m" "Parsec" nil 
+    ( pc      "3.0856775854*10^16 m" "Parsec  (**)" nil
               "3.0856775854 10^16 m (*)") ;; (approx) ESUWM
     ( nmi     "1852 m"               "Nautical Mile" )
     ( fath    "6 ft"                 "Fathom" )
     ( fur     "660 ft"               "Furlong")
     ( mu      "1 um"                 "Micron" )
     ( mil     "(1/1000) in"          "Mil" )
-    ( point   "(1/72) in"            "Point (1/72 inch)" )
+    ( point   "(1/72) in"            "Point  (PostScript convention)" )
     ( Ang     "10^(-10) m"           "Angstrom" )
     ( mfi     "mi+ft+in"             "Miles + feet + inches" )
     ;; TeX lengths
-    ( texpt   "(100/7227) in"        "Point (TeX conventions)" )
-    ( texpc   "12 texpt"             "Pica" )
-    ( texbp   "point"                "Big point (TeX conventions)" )
-    ( texdd   "(1238/1157) texpt"    "Didot point" )
-    ( texcc   "12 texdd"             "Cicero" )
-    ( texsp   "(1/65536) texpt"      "Scaled TeX point" )
+    ( texpt   "(100/7227) in"        "Point  (TeX convention) (**)" )
+    ( texpc   "12 texpt"             "Pica  (TeX convention) (**)" )
+    ( texbp   "point"                "Big point  (TeX convention) (**)" )
+    ( texdd   "(1238/1157) texpt"    "Didot point  (TeX convention) (**)" )
+    ( texcc   "12 texdd"             "Cicero  (TeX convention) (**)" )
+    ( texsp   "(1/65536) texpt"      "Scaled TeX point (TeX convention) (**)" )
 
     ;; Area
     ( hect    "10000 m^2"            "*Hectare" )
     ( l       "L"                    "Liter" )
     ( gal     "4 qt"                 "US Gallon" )
     ( qt      "2 pt"                 "Quart" )
-    ( pt      "2 cup"                "Pint" )
+    ( pt      "2 cup"                "Pint (**)" )
     ( cup     "8 ozfl"               "Cup" )
     ( ozfl    "2 tbsp"               "Fluid Ounce" )
     ( floz    "2 tbsp"               "Fluid Ounce" )
     ( tbsp    "3 tsp"                "Tablespoon" )
     ;; ESUWM defines a US gallon as 231 in^3.
     ;; That gives the following exact value for tsp.
-    ( tsp     "492892159375*10^(-11) ml" "Teaspoon" nil 
+    ( tsp     "492892159375*10^(-11) ml" "Teaspoon" nil
               "4.92892159375 ml")
     ( vol     "tsp+tbsp+ozfl+cup+pt+qt+gal" "Gallons + ... + teaspoons" nil
               "tsp+tbsp+ozfl+cup+pt+qt+gal")
     ( galC    "galUK"                "Canadian Gallon" )
-    ( galUK   "454609*10^(-5) L"     "UK Gallon" nil 
+    ( galUK   "454609*10^(-5) L"     "UK Gallon" nil
               "4.54609 L") ;; NIST
 
     ;; Time
     ( c       "299792458 m/s"        "Speed of light" ) ;;; CODATA
 
     ;; Acceleration
-    ( ga      "980665*10^(-5) m/s^2" "*\"g\" acceleration" nil 
+    ( ga      "980665*10^(-5) m/s^2" "*\"g\" acceleration" nil
               "9.80665 m / s^2") ;; CODATA
 
     ;; Mass
     ( g       nil                    "*Gram" )
     ( lb      "16 oz"                "Pound (mass)" )
-    ( oz      "28349523125*10^(-9) g" "Ounce (mass)" nil 
+    ( oz      "28349523125*10^(-9) g" "Ounce (mass)" nil
               "28.349523125 g") ;; ESUWM
     ( ton     "2000 lb"              "Ton" )
     ( tpo     "ton+lb+oz"            "Tons + pounds + ounces (mass)" )
     ( t       "1000 kg"              "Metric ton" )
-    ( tonUK   "10160469088*10^(-7) kg" "UK ton" nil 
+    ( tonUK   "10160469088*10^(-7) kg" "UK ton" nil
               "1016.0469088 kg") ;; ESUWM
     ( lbt     "12 ozt"               "Troy pound" )
-    ( ozt     "311034768*10^(-7) g"        "Troy ounce" nil 
+    ( ozt     "311034768*10^(-7) g"        "Troy ounce" nil
               "31.10347680 g") ;; ESUWM, 1/12 exact value for lbt
-    ( ct      "(2/10) g"             "Carat" nil 
+    ( ct      "(2/10) g"             "Carat" nil
               "0.2 g") ;; ESUWM
-    ( u       "1.660538782*10^(-27) kg"    "Unified atomic mass" nil 
+    ( u       "1.660538782*10^(-27) kg"    "Unified atomic mass" nil
               "1.660538782 10^-27 kg (*)");;(approx) CODATA
 
     ;; Force
     ( gf      "ga g"                 "Gram (force)" )
     ( lbf     "ga lb"                "Pound (force)" )
     ( kip     "1000 lbf"             "Kilopound (force)" )
-    ( pdl     "138254954376*10^(-12) N" "Poundal" nil 
+    ( pdl     "138254954376*10^(-12) N" "Poundal" nil
               "0.138254954376 N") ;; ESUWM
 
     ;; Energy
     ( J       "N m"                  "*Joule" )
     ( erg     "10^(-7) J"            "Erg" )
-    ( cal     "41868*10^(-4) J"      "International Table Calorie" nil 
+    ( cal     "41868*10^(-4) J"      "International Table Calorie" nil
               "4.1868 J") ;; NIST
-    ( calth   "4184*10^(-3) J"       "Thermochemical Calorie" nil 
+    ( calth   "4184*10^(-3) J"       "Thermochemical Calorie" nil
               "4.184 J") ;; NIST
     ( Cal     "1000 cal"             "Large Calorie")
-    ( Btu     "105505585262*10^(-8) J" "International Table Btu" nil 
+    ( Btu     "105505585262*10^(-8) J" "International Table Btu" nil
               "1055.05585262 J") ;; ESUWM
     ( eV      "ech V"                "Electron volt" )
     ( ev      "eV"                   "Electron volt" )
     ( atm     "101325 Pa"            "Standard atmosphere" ) ;; CODATA
     ( Torr    "(1/760) atm"          "Torr")
     ( mHg     "1000 Torr"            "Meter of mercury" )
-    ( inHg    "254*10^(-1) mmHg"     "Inch of mercury" nil 
+    ( inHg    "254*10^(-1) mmHg"     "Inch of mercury" nil
               "25.4 mmHg")
-    ( inH2O   "2.490889*10^2 Pa"        "Inch of water" nil 
+    ( inH2O   "2.490889*10^2 Pa"        "Inch of water" nil
               "2.490889 10^2 Pa (*)") ;;(approx) NIST
     ( psi     "lbf/in^2"             "Pounds per square inch" )
 
     ( C       "A s"                   "Coulomb" )
     ( Fdy     "ech Nav"               "Faraday" )
     ( e       "ech"                   "Elementary charge" )
-    ( ech     "1.602176487*10^(-19) C"     "Elementary charge" nil 
+    ( ech     "1.602176487*10^(-19) C"     "Elementary charge" nil
               "1.602176487 10^-19 C (*)") ;;(approx) CODATA
     ( V       "W/A"                   "Volt" )
     ( ohm     "V/A"                   "Ohm" )
+    ( Ω       "ohm"                   "Ohm" )
     ( mho     "A/V"                   "Mho" )
     ( S       "A/V"                   "Siemens" )
     ( F       "C/V"                   "Farad" )
 
     ;; Other physical quantities
     ;; The values are from CODATA, and are approximate.
-    ( h       "6.62606896*10^(-34) J s"     "*Planck's constant" nil 
+    ( h       "6.62606896*10^(-34) J s"     "*Planck's constant" nil
               "6.62606896 10^-34 J s (*)")
     ( hbar    "h / (2 pi)"                  "Planck's constant" ) ;; Exact
     ( mu0     "4 pi 10^(-7) H/m"            "Permeability of vacuum") ;; Exact
+    ( μ0      "mu0"                         "Permeability of vacuum") ;; Exact
     ( eps0    "1 / (mu0 c^2)"               "Permittivity of vacuum" )
-    ( G       "6.67428*10^(-11) m^3/(kg s^2)"    "Gravitational constant" nil 
+    ( ε0      "eps0"                        "Permittivity of vacuum" )
+    ( G       "6.67428*10^(-11) m^3/(kg s^2)"    "Gravitational constant" nil
               "6.67428 10^-11 m^3/(kg s^2) (*)")
-    ( Nav     "6.02214179*10^(23) / mol"    "Avagadro's constant" nil 
+    ( Nav     "6.02214179*10^(23) / mol"    "Avogadro's constant" nil
               "6.02214179 10^23 / mol (*)")
-    ( me      "9.10938215*10^(-31) kg"      "Electron rest mass" nil 
+    ( me      "9.10938215*10^(-31) kg"      "Electron rest mass" nil
               "9.10938215 10^-31 kg (*)")
-    ( mp      "1.672621637*10^(-27) kg"     "Proton rest mass" nil 
+    ( mp      "1.672621637*10^(-27) kg"     "Proton rest mass" nil
               "1.672621637 10^-27 kg (*)")
-    ( mn      "1.674927211*10^(-27) kg"     "Neutron rest mass" nil 
+    ( mn      "1.674927211*10^(-27) kg"     "Neutron rest mass" nil
               "1.674927211 10^-27 kg (*)")
-    ( mmu     "1.88353130*10^(-28) kg"      "Muon rest mass" nil 
+    ( mmu     "1.88353130*10^(-28) kg"      "Muon rest mass" nil
               "1.88353130 10^-28 kg (*)")
-    ( Ryd     "10973731.568527 /m"          "Rydberg's constant" nil 
+    ( mμ      "mmu"                         "Muon rest mass" nil
+              "1.88353130 10^-28 kg (*)")
+    ( Ryd     "10973731.568527 /m"          "Rydberg's constant" nil
               "10973731.568527 /m (*)")
-    ( k       "1.3806504*10^(-23) J/K"      "Boltzmann's constant" nil 
+    ( k       "1.3806504*10^(-23) J/K"      "Boltzmann's constant" nil
               "1.3806504 10^-23 J/K (*)")
-    ( alpha   "7.2973525376*10^(-3)"        "Fine structure constant" nil 
+    ( alpha   "7.2973525376*10^(-3)"        "Fine structure constant" nil
+              "7.2973525376 10^-3 (*)")
+    ( α       "alpha"                        "Fine structure constant" nil
               "7.2973525376 10^-3 (*)")
-    ( muB     "927.400915*10^(-26) J/T"     "Bohr magneton" nil 
+    ( muB     "927.400915*10^(-26) J/T"     "Bohr magneton" nil
               "927.400915 10^-26 J/T (*)")
-    ( muN     "5.05078324*10^(-27) J/T"     "Nuclear magneton" nil 
+    ( muN     "5.05078324*10^(-27) J/T"     "Nuclear magneton" nil
               "5.05078324 10^-27 J/T (*)")
-    ( mue     "-928.476377*10^(-26) J/T"    "Electron magnetic moment" nil 
+    ( mue     "-928.476377*10^(-26) J/T"    "Electron magnetic moment" nil
               "-928.476377 10^-26 J/T (*)")
-    ( mup     "1.410606662*10^(-26) J/T"    "Proton magnetic moment" nil 
+    ( mup     "1.410606662*10^(-26) J/T"    "Proton magnetic moment" nil
               "1.410606662 10^-26 J/T (*)")
-    ( R0      "8.314472 J/(mol K)"          "Molar gas constant" nil 
+    ( R0      "8.314472 J/(mol K)"          "Molar gas constant" nil
               "8.314472 J/(mol K) (*)")
-    ( V0      "22.710981*10^(-3) m^3/mol"   "Standard volume of ideal gas" nil 
-              "22.710981 10^-3 m^3/mol (*)")))
+    ( V0      "22.710981*10^(-3) m^3/mol"   "Standard volume of ideal gas" nil
+              "22.710981 10^-3 m^3/mol (*)")
+    ;; Logarithmic units
+    ( Np      nil    "*Neper")
+    ( dB      "(ln(10)/20) Np" "decibel")))
 
 
 (defvar math-additional-units nil
   "*Additional units table for user-defined units.
-Must be formatted like math-standard-units.
-If this is changed, be sure to set math-units-table to nil to ensure
+Must be formatted like `math-standard-units'.
+If you change this, be sure to set `math-units-table' to nil to ensure
 that the combined units table will be rebuilt.")
 
 (defvar math-unit-prefixes
@@ -316,6 +325,7 @@ that the combined units table will be rebuilt.")
      ( ?c  (^ 10 -2)  "Centi"  )
      ( ?m  (^ 10 -3)  "Milli"  )
      ( ?u  (^ 10 -6)  "Micro"  )
+     ( ?μ  (^ 10 -6)  "Micro"  )
      ( ?n  (^ 10 -9)  "Nano"   )
      ( ?p  (^ 10 -12) "Pico"   )
      ( ?f  (^ 10 -15) "Femto"  )
@@ -330,7 +340,8 @@ that the combined units table will be rebuilt.")
      ( cgs   ( ( m   '(* (var cm var-cm) 100 ) ) ) )))
 
 (defvar math-units-table nil
-  "Internal units table derived from math-defined-units.
+  "Internal units table.
+Derived from `math-standard-units' and `math-additional-units'.
 Entries are (SYMBOL EXPR DOC-STRING TEMP-TYPE BASE-UNITS).")
 
 (defvar math-units-table-buffer-valid nil)
@@ -348,7 +359,7 @@ Entries are (SYMBOL EXPR DOC-STRING TEMP-TYPE BASE-UNITS).")
 (defun calc-quick-units ()
   (interactive)
   (calc-slow-wrapper
-   (let* ((num (- last-command-char ?0))
+   (let* ((num (- last-command-event ?0))
          (pos (if (= num 0) 10 num))
          (units (calc-var-value 'var-Units))
          (expr (calc-top-n 1)))
@@ -580,8 +591,8 @@ If EXPR is nil, return nil."
        (let ((name (or (nth 2 u) (symbol-name (car u)))))
          (if (eq (aref name 0) ?\*)
              (setq name (substring name 1)))
-         (if (string-match "[^a-zA-Z0-9']" name)
-             (if (string-match "^[a-zA-Z0-9' ()]*$" name)
+         (if (string-match "[^a-zA-Zα-ωΑ-Ω0-9']" name)
+             (if (string-match "^[a-zA-Zα-ωΑ-Ω0-9' ()]*$" name)
                  (while (setq pos (string-match "[ ()]" name))
                    (setq name (concat (substring name 0 pos)
                                       (if (eq (aref name pos) 32) "-" "")
@@ -591,7 +602,7 @@ If EXPR is nil, return nil."
              (setq name (concat (nth 2 (assq (aref (symbol-name
                                                     (nth 1 expr)) 0)
                                              math-unit-prefixes))
-                                (if (and (string-match "[^a-zA-Z0-9']" name)
+                                (if (and (string-match "[^a-zA-Zα-ωΑ-Ω0-9']" name)
                                          (not (memq (car u) '(mHg gf))))
                                     (concat "-" name)
                                   (downcase name)))))
@@ -694,8 +705,7 @@ If EXPR is nil, return nil."
   (setq math-units-table nil)
   (let ((buf (get-buffer "*Units Table*")))
     (and buf
-        (save-excursion
-          (set-buffer buf)
+        (with-current-buffer buf
           (save-excursion
             (goto-char (point-min))
             (if (looking-at "Calculator Units Table")
@@ -863,6 +873,7 @@ If EXPR is nil, return nil."
           (or (eq (nth 1 expr) 'pi)
               (error "Unknown name %s in defining expression for unit %s"
                      (nth 1 expr) (car math-fbu-entry))))
+          ((equal expr '(calcFunc-ln 10)))
          (t (error "Malformed defining expression for unit %s" (car math-fbu-entry))))))
 
 
@@ -1456,6 +1467,7 @@ If EXPR is nil, return nil."
            (calc-float-format '(float 0))
            (calc-group-digits nil)
            (calc-number-radix 10)
+            (calc-twos-complement-mode nil)
            (calc-point-char ".")
            (std nil)
            u name shadowed)
@@ -1522,7 +1534,12 @@ If EXPR is nil, return nil."
               (indent-to 15)
               (insert "   " (nth 2 u) "\n")
               (while (eq (car (car (setq uptr (cdr uptr)))) 0)))
-            (insert "\n"))
+            (insert "\n\n")
+            (insert "(**) When in TeX or LaTeX display mode, the TeX specific unit\n"
+                     "names will not use the `tex' prefix; the unit name for a\n"
+                     "TeX point will be `pt' instead of `texpt', for example.\n"
+                     "To avoid conflicts, the unit names for pint and parsec will\n"
+                     "be `pint' and `parsec' instead of `pt' and `pc'."))
          (view-mode)
          (message "Formatting units table...done"))
        (setq math-units-table-buffer-valid t)
@@ -1537,11 +1554,312 @@ If EXPR is nil, return nil."
        (pop-to-buffer (get-buffer "*Units Table*"))
       (display-buffer (get-buffer "*Units Table*")))))
 
+;;; Logarithmic units functions
+
+(defvar math-logunits '((var dB var-dB)
+                        (var Np var-Np)))
+
+(defun math-conditional-apply (fn &rest args)
+  "Evaluate f(args) unless in symbolic mode.
+In symbolic mode, return the list (fn args)."
+  (if calc-symbolic-mode
+      (cons fn args)
+    (apply fn args)))
+
+(defun math-conditional-pow (a b)
+  "Evaluate a^b unless in symbolic mode.
+In symbolic mode, return the list (^ a b)."
+  (if calc-symbolic-mode
+      (list '^ a b)
+    (math-pow a b)))
+
+(defun math-extract-logunits (expr)
+  (if (memq (car-safe expr) '(* /))
+      (cons (car expr)
+           (mapcar 'math-extract-logunits (cdr expr)))
+    (if (memq (car-safe expr) '(^))
+        (list '^ (math-extract-logunits (nth 1 expr)) (nth 2 expr))
+      (if (member expr math-logunits) expr 1))))
+
+(defun math-logunits-add (a b neg power)
+  (let ((aunit (math-simplify (math-extract-logunits a))))
+    (if (not (eq (car-safe aunit) 'var))
+        (calc-record-why "*Improper logarithmic unit" aunit)
+      (let* ((units (math-extract-units a))
+            (acoeff (math-simplify (math-remove-units a)))
+            (bcoeff (math-simplify (math-to-standard-units
+                                    (list '/ b units) nil))))
+        (if (math-units-in-expr-p bcoeff nil)
+            (calc-record-why "*Inconsistent units" nil)
+          (if (and neg
+                   (or (math-lessp acoeff bcoeff)
+                       (math-equal acoeff bcoeff)))
+              (calc-record-why "*Improper coefficients" nil)
+            (math-mul 
+             (if (equal aunit '(var dB var-dB))
+                 (let ((coef (if power 10 20)))
+                   (math-mul coef
+                             (math-conditional-apply 'calcFunc-log10
+                              (if neg
+                                  (math-sub
+                                   (math-conditional-pow 10 (math-div acoeff coef))
+                                   (math-conditional-pow 10 (math-div bcoeff coef)))
+                                (math-add
+                                 (math-conditional-pow 10 (math-div acoeff coef))
+                                 (math-conditional-pow 10 (math-div bcoeff coef)))))))
+               (let ((coef (if power 2 1)))
+                 (math-div
+                  (math-conditional-apply 'calcFunc-ln
+                   (if neg
+                       (math-sub
+                        (math-conditional-apply 'calcFunc-exp (math-mul coef acoeff))
+                        (math-conditional-apply 'calcFunc-exp (math-mul coef bcoeff)))
+                     (math-add
+                      (math-conditional-apply 'calcFunc-exp (math-mul coef acoeff))
+                      (math-conditional-apply 'calcFunc-exp (math-mul coef bcoeff)))))
+                  coef)))
+             units)))))))
+
+(defun calcFunc-lufieldplus (a b)
+  (math-logunits-add a b nil nil))
+
+(defun calcFunc-lupowerplus (a b)
+  (math-logunits-add a b nil t))
+
+(defun calcFunc-lufieldminus (a b)
+  (math-logunits-add a b t nil))
+
+(defun calcFunc-lupowerminus (a b)
+  (math-logunits-add a b t t))
+
+(defun calc-logunits-add (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-inverse)
+       (if (calc-is-hyperbolic)
+           (calc-binary-op "lu-" 'calcFunc-lufieldminus arg)
+         (calc-binary-op "lu-" 'calcFunc-lupowerminus arg))
+     (if (calc-is-hyperbolic)
+         (calc-binary-op "lu+" 'calcFunc-lufieldplus arg)
+       (calc-binary-op "lu+" 'calcFunc-lupowerplus arg)))))
+
+(defun calc-logunits-sub (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-inverse)
+       (if (calc-is-hyperbolic)
+           (calc-binary-op "lu+" 'calcFunc-lufieldplus arg)
+         (calc-binary-op "lu+" 'calcFunc-lupowerplus arg))
+     (if (calc-is-hyperbolic)
+         (calc-binary-op "lu-" 'calcFunc-lufieldminus arg)
+       (calc-binary-op "lu-" 'calcFunc-lupowerminus arg)))))
+
+(defun math-logunits-mul (a b power)
+  (let (logunit coef units number)
+    (cond
+     ((and
+       (setq logunit (math-simplify (math-extract-logunits a)))
+       (eq (car-safe logunit) 'var)
+       (eq (math-simplify (math-extract-units b)) 1))
+      (setq coef (math-simplify (math-remove-units a))
+            units (math-extract-units a)
+            number b))
+     ((and
+       (setq logunit (math-simplify (math-extract-logunits b)))
+       (eq (car-safe logunit) 'var)
+       (eq (math-simplify (math-extract-units a)) 1))
+      (setq coef (math-simplify (math-remove-units b))
+            units (math-extract-units b)
+            number a))
+     (t (setq logunit nil)))
+    (if logunit
+        (cond
+         ((equal logunit '(var dB var-dB))
+          (math-simplify
+           (math-mul
+            (math-add
+             coef 
+             (math-mul (if power 10 20)
+                       (math-conditional-apply 'calcFunc-log10 number)))
+            units)))
+         (t
+          (math-simplify
+           (math-mul
+            (math-add
+             coef 
+             (math-div (math-conditional-apply 'calcFunc-ln number) (if power 2 1)))
+            units))))
+      (calc-record-why "*Improper units" nil))))
+
+(defun math-logunits-divide (a b power)
+  (let ((logunit (math-simplify (math-extract-logunits a))))
+    (if (not (eq (car-safe logunit) 'var))
+        (calc-record-why "*Improper logarithmic unit" logunit)
+      (if (math-units-in-expr-p b nil)
+          (calc-record-why "*Improper units quantity" b)
+        (let* ((units (math-extract-units a))
+               (coef (math-simplify (math-remove-units a))))
+          (cond
+           ((equal logunit '(var dB var-dB))
+            (math-simplify
+             (math-mul
+              (math-sub
+               coef 
+               (math-mul (if power 10 20)
+                         (math-conditional-apply 'calcFunc-log10 b)))
+              units)))
+         (t
+          (math-simplify
+           (math-mul
+            (math-sub
+             coef 
+             (math-div (math-conditional-apply 'calcFunc-ln b) (if power 2 1)))
+            units)))))))))
+
+(defun calcFunc-lufieldtimes (a b)
+  (math-logunits-mul a b nil))
+
+(defun calcFunc-lupowertimes (a b)
+  (math-logunits-mul a b t))
+
+(defun calc-logunits-mul (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-inverse)
+       (if (calc-is-hyperbolic)
+           (calc-binary-op "lu/" 'calcFunc-lufielddiv arg)
+         (calc-binary-op "lu/" 'calcFunc-lupowerdiv arg))
+     (if (calc-is-hyperbolic)
+         (calc-binary-op "lu*" 'calcFunc-lufieldtimes arg)
+       (calc-binary-op "lu*" 'calcFunc-lupowertimes arg)))))
+
+(defun calcFunc-lufielddiv (a b)
+  (math-logunits-divide a b nil))
+
+(defun calcFunc-lupowerdiv (a b)
+  (math-logunits-divide a b t))
+
+(defun calc-logunits-divide (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-inverse)
+       (if (calc-is-hyperbolic)
+           (calc-binary-op "lu*" 'calcFunc-lufieldtimes arg)
+         (calc-binary-op "lu*" 'calcFunc-lupowertimes arg))
+     (if (calc-is-hyperbolic)
+         (calc-binary-op "lu/" 'calcFunc-lufielddiv arg)
+       (calc-binary-op "lu/" 'calcFunc-lupowerdiv arg)))))
+
+(defun math-logunits-quant (val ref power)
+  (let* ((units (math-simplify (math-extract-units val)))
+         (lunit (math-simplify (math-extract-logunits units))))
+    (if (not (eq (car-safe lunit) 'var))
+        (calc-record-why "*Improper logarithmic unit" lunit)
+      (let ((runits (math-simplify (math-div units lunit)))
+            (coeff (math-simplify (math-div val units))))
+        (math-mul
+         (if (equal lunit '(var dB var-dB))
+             (math-mul 
+              ref
+              (math-conditional-pow 
+               10
+               (math-div
+                coeff
+                (if power 10 20))))
+           (math-mul 
+            ref
+            (math-conditional-apply 'calcFunc-exp
+             (if power 
+                 (math-mul 2 coeff)
+               coeff))))
+         runits)))))
+
+(defvar calc-logunits-field-reference)
+(defvar calc-logunits-power-reference)
+
+(defun calcFunc-fieldquant (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-field-reference)))
+  (math-logunits-quant val ref nil))
+
+(defun calcFunc-powerquant (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-power-reference)))
+  (math-logunits-quant val ref t))
+
+(defun calc-logunits-quantity (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-hyperbolic)
+       (if (calc-is-option)
+           (calc-binary-op "lupq" 'calcFunc-fieldquant arg)
+         (calc-unary-op "lupq" 'calcFunc-fieldquant arg))
+     (if (calc-is-option)
+         (calc-binary-op "lufq" 'calcFunc-powerquant arg)
+       (calc-unary-op "lufq" 'calcFunc-powerquant arg)))))
+
+(defun math-logunits-level (val ref db power)
+  "Compute the value of VAL in decibels or nepers."
+      (let* ((ratio (math-simplify-units (math-div val ref)))
+             (ratiou (math-simplify-units (math-remove-units ratio)))
+             (units (math-simplify (math-extract-units ratio))))
+        (math-mul
+         (if db
+             (math-mul
+              (math-mul (if power 10 20)
+                        (math-conditional-apply 'calcFunc-log10 ratiou))
+              '(var dB var-dB))
+           (math-mul
+            (math-div (math-conditional-apply 'calcFunc-ln ratiou) (if power 2 1))
+            '(var Np var-Np)))
+         units)))
+
+(defun calcFunc-dbfieldlevel (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-field-reference)))
+  (math-logunits-level val ref t nil))
+
+(defun calcFunc-dbpowerlevel (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-power-reference)))
+  (math-logunits-level val ref t t))
+
+(defun calcFunc-npfieldlevel (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-field-reference)))
+  (math-logunits-level val ref nil nil))
+
+(defun calcFunc-nppowerlevel (val &optional ref)
+  (unless ref
+    (setq ref (math-read-expr calc-logunits-power-reference)))
+  (math-logunits-level val ref nil t))
+
+(defun calc-logunits-dblevel (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-hyperbolic)
+       (if (calc-is-option)
+           (calc-binary-op "ludb" 'calcFunc-dbfieldlevel arg)
+         (calc-unary-op "ludb" 'calcFunc-dbfieldlevel arg))
+     (if (calc-is-option)
+         (calc-binary-op "ludb" 'calcFunc-dbpowerlevel arg)
+       (calc-unary-op "ludb" 'calcFunc-dbpowerlevel arg)))))
+
+(defun calc-logunits-nplevel (arg)
+  (interactive "P")
+  (calc-slow-wrapper
+   (if (calc-is-hyperbolic)
+       (if (calc-is-option)
+           (calc-binary-op "lunp" 'calcFunc-npfieldlevel arg)
+         (calc-unary-op "lunp" 'calcFunc-npfieldlevel arg))
+     (if (calc-is-option)
+         (calc-binary-op "lunp" 'calcFunc-nppowerlevel arg)
+       (calc-unary-op "lunp" 'calcFunc-nppowerlevel arg)))))
+
 (provide 'calc-units)
 
-;; Local Variables:
-;; coding: iso-latin-1
+;; Local variables:
+;; coding: utf-8
 ;; End:
 
-;; arch-tag: e993314f-3adc-4191-be61-4ef8874881c4
 ;;; calc-units.el ends here