emacs.d/lp/calc.org

432 lines
14 KiB
Org Mode

#+TITLE: calc examples
# #+DATE: <2013-08-09 Fri>
#+AUTHOR: Derek Feichtinger
#+EMAIL: derek.feichtinger@psi.ch
#+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline
#+OPTIONS: author:t c:nil creator:comment d:(not LOGBOOK) date:t e:t
#+OPTIONS: email:nil f:t inline:t num:t p:nil pri:nil stat:t tags:t
#+OPTIONS: tasks:t tex:t timestamp:t toc:t todo:t |:t
#+CREATOR: Emacs 24.3.1 (Org mode 8.0.7)
#+DESCRIPTION:
#+EXCLUDE_TAGS: noexport
#+KEYWORDS:
#+LANGUAGE: en
#+SELECT_TAGS: export
# By default I do not want that source code blocks are evaluated on export. Usually
# I want to evaluate them interactively and retain the original results.
#+PROPERTY: header-args :eval never-export
* Version information
#+BEGIN_SRC emacs-lisp :results output :exports both
(princ (concat (format "Emacs version: %s\n" (emacs-version))
(format "org version: %s\n" (org-version))))
#+END_SRC
#+RESULTS:
: Emacs version: GNU Emacs 26.2 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.22.30)
: of 2019-04-14
: org version: 9.3.7
* General
- refer to the [[info:calc#Top][Calc info pages]]
- Note that, unlike in usual computer notation, multiplication binds
more strongly than division: `a*b/c*d' is equivalent to
`(a*b)/(c*d)'
- [[https://github.com/SueDNymme/emacs-calc-qref][Nice reference sheet]] on calc maintained by Sue D. Nymme
* babel Calc
Not too useful, yet. Embedded calc certainly is better for
inlining math in documents. Using Elisp to directly interacting with
calc also is more powerful.
#+BEGIN_SRC calc
24
3
'/
#+END_SRC
#+RESULTS:
: 8
- solving an equation
#+BEGIN_SRC calc :exports both
fsolve(x*2+x=4,x)
#+END_SRC
#+RESULTS:
: x = 1.33333333333
- solving a linear system of equations
#+BEGIN_SRC calc
fsolve([x + y = a, x - y = b],[x,y])
#+END_SRC
#+RESULTS:
: [x = a + (b - a) / 2, y = (a - b) / 2]
* Calc from lisp
- [[info:calc#Calling%20Calc%20from%20Your%20Programs][Emacs Info Manual: Calling Calc from your programs]]
- nice blog post on [[http://nullprogram.com/blog/2015/10/30/][RSA cryptography using emacs Calc]] by Chris
Wellons on his [[http://nullprogram.com/][nullprogram]] blog. Contains examples on =calc-eval=
usage.
** basic use of calc-eval
The variables in formulas are replaced by the additional arguments. Arguments can be given as string or number.
#+BEGIN_SRC emacs-lisp :results output
(print (calc-eval "2^$1 - 1 + $2" nil 3 5))
(print (calc-eval "2^$1 - 1" nil 128))
(print (calc-eval "$1 < $2" 'pred "4000" "5000"))
(print (calc-eval "$1 > $2" 'pred "4000" "5000"))
(print (calc-eval "$1 < $2" nil "4000" "5000"))
(print (calc-eval "$1 > $2" nil "4000" "5000"))
(print (calc-eval "nextprime($1)" nil "100000000000000000"))
;; radix can be chosen by separating radix by # from number
(print (calc-eval "16#deadbeef"))
(print (calc-eval "2#1111"))
#+END_SRC
#+RESULTS:
#+begin_example
"12"
"340282366920938463463374607431768211455"
t
nil
"1"
"0"
"100000000000000003"
"3735928559"
"15"
#+end_example
The second argument serves as a separator if the result is a list of expressions. By default the list
is printed comma-separated.
#+BEGIN_SRC emacs-lisp :results output
(print (calc-eval "10+5, 7*3, 5/2"))
(print (calc-eval "10+5, 7*3, 5/2" ";"))
(print (calc-eval "10+5, 7*3, 5/2" "___"))
#+END_SRC
#+RESULTS:
:
: "15, 21, 2.5"
:
: "15;21;2.5"
:
: "15___21___2.5"
** using calc-eval to supply raw calc objects as input to calc internal functions
calc internal functions deal with /raw/ calc objects. These can also be obtained through =calc-eval= by
passing the =raw= as the second argument.
#+BEGIN_SRC emacs-lisp
(calc-eval (math-convert-units (calc-eval "10 m" 'raw)
(calc-eval "ft" 'raw)))
#+END_SRC
#+RESULTS:
: 32.8083989501 ft
#+BEGIN_SRC emacs-lisp
(calc-eval (math-simplify-units (calc-eval "10 m + 1 mm" 'raw)))
#+END_SRC
#+RESULTS:
: 10.001 m
Todo: I do not know how the second arg to math-to-standard-units is used. Nil
works as well as any other list, it seems.
#+BEGIN_SRC emacs-lisp
(calc-eval
(math-to-standard-units
(calc-eval "5 J" 'raw) nil))
#+END_SRC
#+RESULTS:
: 5000 g m^2 / s^2
** math-read-exprs returns the AST of an expression
To understand the lisp expressions that will get executed to obtain
a result, one can use the =math-read-exprs= function. It returns an
AST of the expression.
#+BEGIN_SRC emacs-lisp :results verbatim
(math-read-exprs "5 * 6 - 20")
#+END_SRC
#+RESULTS:
: ((- (* 5 6) 20))
#+BEGIN_SRC emacs-lisp :results verbatim
(math-read-exprs "x=vsum(1, 2, 3)")
#+END_SRC
#+RESULTS:
: ((calcFunc-eq (var x var-x) (calcFunc-vsum 1 2 3)))
Lets try executing the lisp (note that the result is enclosed by an
extra parentheses).
#+begin_src elisp :results verbatim
(calcFunc-eq '(var x var-x) (calcFunc-vsum 1 2 3))
#+end_src
#+RESULTS:
: (calcFunc-eq (var x var-x) 6)
#+begin_src elisp :results verbatim
(calc-eval (calcFunc-eq '(var x var-x) (calcFunc-vsum 1 2 3)))
#+end_src
#+RESULTS:
: "x = 6"
** Stack operations: push, pop and top
- =push= pushes the element onto the stack
- =pop= deletes as many elements from the stack as the preceding integer argument indicates
- =0 pop= is convenient for finding out the size of the stack
- =top= retrieves the value at the indicated position of the stack
#+BEGIN_SRC emacs-lisp :results output :exports both
(princ (format "Size of the stack: %s\n" (calc-eval 0 'pop)))
(calc-eval "10 ft" 'push)
(calc-eval "20 ft" 'push)
(calc-eval "30 ft" 'push)
(princ (format "After 3*push: Size of the stack: %s (top element: %s)\n"
(calc-eval 0 'pop)
(calc-eval 1 'top)))
(princ (format "element on second level of stack: %s\n" (calc-eval 2 'top)))
(calc-eval 2 'pop)
(princ (format "After 3*push: Size of the stack: %s (top element: %s)\n"
(calc-eval 0 'pop)
(calc-eval 1 'top)))
(calc-eval 1 'pop)
#+END_SRC
#+RESULTS:
: Size of the stack: 5
: After 3*push: Size of the stack: 8 (top element: 30 ft)
: element on second level of stack: 20 ft
: After 3*push: Size of the stack: 6 (top element: 10 ft)
** executing functions on the stack
#+BEGIN_SRC emacs-lisp :results output :exports both
(calc-eval "10 ft" 'push)
(calc-base-units)
;; retrieve the value from the stack as a string. Note that it still stays on the stack!
(print (calc-eval 1 'top))
;; clean the value from the stack
(calc-eval 1 'pop)
#+END_SRC
#+RESULTS:
:
: "3.048 m"
It is also possible to execute Calc keyboard macros, i.e. the string is interpreted as
interactive keyboard strokes in calc mode.
#+BEGIN_SRC emacs-lisp :results output :exports both
(calc-eval "10 ft" 'push)
;; calc keys for base unit conversion
(calc-eval "ub" 'macro)
(print (calc-eval 1 'top))
;; pop one item from stack
(calc-eval "\C-d" 'macro)
#+END_SRC
#+RESULTS:
:
: "3.048 m"
** Some other examples of using calc in lisp
#+BEGIN_SRC emacs-lisp :results output
(princ
(format "%s %s"
(calc-eval "deg(37@ 26' 36.42)")
;; now using pure lisp
(math-format-number
(calcFunc-deg '(hms 37 26 (float 3642 -2))))))
#+END_SRC
#+RESULTS:
: 37.44345 37.44345
* Org configurations for Calc
- https://emacs.stackexchange.com/questions/59179/specify-precision-using-calc-in-org-mode-spreadsheets/59181#59181
The variable org-calc-default-modes is used to customize Calc for org usage
#+begin_src elisp
(defcustom org-calc-default-modes
'(calc-internal-prec 12
calc-float-format (float 8)
calc-angle-mode deg
calc-prefer-frac nil
calc-symbolic-mode nil
calc-date-format (YYYY "-" MM "-" DD " " Www (" " hh ":" mm))
calc-display-working-message t)
"List with Calc mode settings for use in `calc-eval' for table formulas.
The list must contain alternating symbols (Calc modes variables and values).
Don't remove any of the default settings, just change the values. Org mode
relies on the variables to be present in the list."
:group 'org-table-calculation
:type 'plist)
#+end_src
* Calc usage in tables
** Unit conversions by defining new functions with defmath
- from http://article.gmane.org/gmane.emacs.orgmode/93489
Displaying all calc units in a buffer can be obtained by executing
#+BEGIN_SRC emacs-lisp :exports source
(calc-view-units-table 1)
#+END_SRC
Calc preserves units and variables in table operations.
| distance | time | speed |
|----------+--------+-------------|
| 3 km | 2.5 hr | 1.2 km / hr |
#+TBLFM: @2$3=$1/$2
| speed | simplified speed |
|--------------+------------------|
| 40km / 2.5hr | 16. km / hr |
#+TBLFM: @2$2=usimplify($1)
We can also decide to use calc via its elisp api. To understand
the following lisp formula that involves calc internal functions
q.v. the [[Calc from lisp]] section.
| km | ft |
|-------+---------|
| 2.5km | 8202.10 |
#+TBLFM: $2='(calc-eval (math-convert-units (calc-eval $1 'raw) (calc-eval "ft" 'raw))); %.2f
Defining a new calc function for unit conversion with defmath
#+BEGIN_SRC emacs-lisp
(defmath uconv (expr target-units &optional pure)
(math-convert-units expr target-units pure))
#+END_SRC
#+RESULTS:
: calcFunc-uconv
| km | ft |
|--------+--------------|
| 2.5 km | 8202.0997 ft |
#+TBLFM: $2=uconv($1, ft)
Using the units from the table header (if the 3rd arg is given to
uconv, the output is stripped of the unit):
| km | ft |
|-----+-----------|
| 2.5 | 8202.0997 |
#+TBLFM: $2 = uconv($1 * @<$1, @<$2, t)
The standard calc function usimplify also works for this use
case:
| km | ft |
|-----+-----------|
| 2.5 | 8202.0997 |
#+TBLFM: $2 = usimplify($1 * @<$1 / @<$2)
A lisp equivalent of the above
#+begin_src elisp
(calc-eval "usimplify(2.5 km / ft)")
#+end_src
#+RESULTS:
: 8202.09973753
Let's define a function that converts to base units
#+begin_src elisp
(defmath ustd (expr) (math-simplify-units (math-to-standard-units expr nil)))
#+end_src
#+RESULTS:
: calcFunc-ustd
| distance | time | speed | std unit speed | speed in ft/s |
|----------+--------+-------------+------------------+------------------|
| 3 km | 2.5 hr | 1.2 km / hr | 0.33333333 m / s | 1.0936133 ft / s |
#+TBLFM: @2$3=$1/$2::@2$4=ustd($3)::@2$5=uconv($-1, ft/s)
* Some standard Calc functions that can be used in formulas
- [[info:calc#Formulas]]
- factorial: $6! => 720 $ also fact(6) can be used in writing
- find: $ find([5, 6, 7, 8], 6) => 2 $
- power: $pow(2, 3) => 8 $ $2^3 => 8 $
- modulo: $mod(10, 3) => 1$ $10 % 3 => 1 $
- binomial coefficient: $choose(3, 2) => 3$
- random numbers: $random(10) => 7$
- binomial distribution: the result (`utpb(x,n,p)') is the
probability that an event will occur X or more times out of N
trials, if its probability of occurring in any given trial is P:
$utpb(2, 6, 1/6) => 0.263224451304$
- gaussian distribution with mean m and stdev s. Probability that a normal
distributed random variable will exceed x: uttn(x,m,s):
$utpn(0.2b, 0, 0.5) => 0.34457825839$
- http://www-zeuthen.desy.de/~kolanosk/smd_ss02/skripte/
- prime factorisation $ prfac(9370) => [2, 5, 937] $
** Time calculations
q.v. [[info:calc#Date%20Arithmetic][info:calc#Date Arithmetic]]
- $now(0) => <11:03:18pm Sun Aug 11, 2013>$
- $now() => <10:48:31pm Wed Jun 28, 2017> $
- Using calc HMS forms
- $ 11@ 41' 15.561" - 11@ 40' 58.096" => 0@ 0' 17.465" $
- The date function with a date form as argument returns a number of days since Jan 1, 1 AD.
The date function with an INT argument yields back a date form.
- $date(<Sun Aug 11, 2013>) => 735091 $
- $date(735091) => <Sun Aug 11, 2013> $
- $date(<10:00am Sun Aug 11, 2013>) => 735091.416667 $
- $date(<Sun Aug 11, 2013>) - date(<Thu Aug 1, 2013>) => 10 $
- $<Sun Aug 11, 2013> - <Thu Aug 1, 2013> => 10 $
- $date(<10:00am Sun Aug 11, 2013>) - date(<9:00am Thu Aug 1, 2013>) => 10.041667 $
- The date function with a comma separated list builds a date or a date/time form
- $date(2017, 6, 26) => <Mon Jun 26, 2017> $
- $date(2017, 6, 26, 11@ 41' 15.561") => <11:41:16am Mon Jun 26, 2017> $
- $date(2017, 6, 26, 11, 41, 15) => <11:41:15am Mon Jun 26, 2017> $
- Not quite clear whether the angular bracket format is any good for more exact calculations
- $ <11:03:18pm Sun Aug 11, 2013> - <11:03:18pm Sun Aug 11, 2013> => 0. $
- $ <11:03:18pm Sun Aug 11, 2013> - <11:02:18pm Sun Aug 11, 2013> => 6.94e-4 $
- $ <11:03:18pm Sun Aug 11, 2013> - <11:03:17pm Sun Aug 11, 2013> => 1.2e-5 $
- $ <11:03:18pm Sun Aug 11, 2013> - <6:03:18pm Sun Aug 11, 2013> => 0.208333 $
- Unix time
- $unixtime(<9:00am Wed Jun 28, 2017>) => 1498640400 $
- $unixtime(1498640400) => <9:00am Wed Jun 28, 2017> $
- $unixtime(now(0)) => 1376262280$
- Julian date
- $julian(date(2017, 6, 26)) => 2457929 $
- $julian(2457929) => <Mon Jun 26, 2017> $
- Using a calc variable
- $ testdate := <11:41:15am Mon Jun 26, 2017> $
- $ year(testdate) => 2017 $
$ date(date(<Fri Apr 16, 2010>) - 10) => <Tue Apr 6, 2010> $
* COMMENT babel settings
Local variables:
org-confirm-babel-evaluate: nil
End: