Jump to content
xisto Community
Sign in to follow this  
mitchellmckain

Emacs Lisp A quick calcualtion tool

Recommended Posts

This tutorial seeks to teach by example since I find this the most efficient way to learn a computer language myself.

 

I want to introduce what has been an extremely valuable tool in my work. It was difficult to decide whether to put it under programming or software, for although the use of it that I am suggesting involves programming in lisp, it is the specific software called emacs that I am introducing as a useful tool. However this could also be considered a tutorial in emacs lisp.

 

You can get a free copy for your pc from

http://www.gnu.org/software/emacs/manual/efaq-w32.html

 

Emacs is a text editor and lisp interpreter combined. First of all it is a powerful and useful alternative to Notepad allowing you to handle control characters in your text files more readily (for example) among many other things. Second, it is a quick and easy way to do calculations without all the preliminaries required in using other programming languages. When you combine the text manipulation commands with the lisp interpreter it becomes a powerful analytical tool.

 

Before explaining this lets start on the basics of lisp programing. Lisp is a calculation based language, meaning that Lisp is composed of expression that are evaluted to produce some calculated result. A lisp program is such an expression and the calculated result of this expression is automatically displayed. A lisp expression is placed between two brackets (also known as parentheses), starting with an operation identifier and followed by the arguments of that operation separated by spaces.

 

Since I am typing this in emacs (in lisp interaction mode) you will see the actual output when the progam is run, which I get by pressing control j after the program (after the last close parentheses) right in the same place where I am typing this text. Emacs just inserts the result of the program on the next line in the text. So after each lisp program I write I will use control j and you will see the output immediately following the lisp program. You can also press control x control e at the end of the program to execute the program and display the results at the bottom of the screen without inserting the result into the text.

 

The following are some examples of simple lisp programs consisting of a single simple mathematical expression.

 

(+ 1 2)

3

 

(+ pi 2)

5.141592653589793

 

(cos pi)

-1.0

 

(log 2)

0.6931471805599453

 

For a y^x calculation you use the expt operation

 

(expt 5 3)

125

 

In order to do multiple operations you nest the parentheses like this

 

(cos (/ pi 4.0))

0.7071067811865476

 

As you can see the cosine is in radians and the logarithm is the natural logarithm. However the common base 10 logarithm is also available and is called log10. But if you want a cosine in degrees, you have to program your own fuction with the "defun" operation.

 

(defun cosd (x)

(cos (* pi (/ x 180.0))))

cosd

 

When you press the control j at the end of this program (after the last parentheses), the interpreter prints just out the name of the function like this and after this you can use this function in other lisp programs like this:

 

(cosd 45)

0.7071067811865476

 

Now that you have been introduced to the lisp language, I will now show you will show you what I found this emacs system so useful for, before continuing with an introductory tutorial in emacs lisp. Emacs is very useful in manipulating and calculating with charts of data in plain text format. For example, the following are the top 10 entries of a webpage listing the 10 brightest stars, with their distance in light years, their visual magnitude, their absolute magnitude, and their spectral classification.

 

Sun - -26.72 4.8 G2V

Sirius Alpha CMa 8.6 -1.46 1.4 A1Vm

Canopus Alpha Car 74 -0.72 -2.5 A9II

Rigil Kentaurus Alpha Cen 4.3 -0.27 4.4 G2V + K1V

Arcturus Alpha Boo 34 -0.04 0.2 K1.5IIIp

Vega Alpha Lyr 25 0.03 0.6 A0Va

Capella Alpha Aur 41 0.08 0.4 G6III + G2III

Rigel Beta Ori ~1400 0.12 -8.1 B81ae

Procyon Alpha CMi 11.4 0.38 2.6 F5IV-V

Achernar Alpha Eri 69 0.46 -1.3 B3Vnp

 

Now if I use tab-to-tab-stop (esc i) command I can line up the numbers to make this easier to read. Actually most of tabulated data like this on the internet is already aligned into collumns so you dont usually have to do this.

 

Sun										  -			  -26.72 4.8  G2V			Sirius Alpha CMa							 8.6			-1.46  1.4  A1Vm		   Canopus Alpha Car							74			 -0.72  -2.5 A9II		   Rigil Kentaurus Alpha Cen					4.3			-0.27  4.4  G2V + K1V	  Arcturus Alpha Boo						   34			 -0.04  0.2  K1.5IIIp	   Vega Alpha Lyr							   25			 0.03   0.6  A0Va		   Capella Alpha Aur							41			 0.08   0.4  G6III + G2III  Rigel Beta Ori							   ~1400		  0.12   -8.1 B81ae		  Procyon Alpha CMi							11.4		   0.38   2.6  F5IV-V		 Achernar Alpha Eri						   69			 0.46   -1.3 B3Vnp		  

 

Now what makes emacs so powerful for charts like this are a set of commands that allow you to cut and paste rectangular portions of text. First we set the rectangle by moving the cursor to one corner and pressing control space then moving the cursor to an opposite corner. Next the control x control k command will cut the rectangle so that when we move the cursor and press control x control y it will paste this rectangle in the new position (after and below the cursor). We can use this on the above chart to move the column of spectral classifications like this.

 

Sun										  G2V			-			  -26.72 4.8  Sirius Alpha CMa							 A1Vm		   8.6			-1.46  1.4  Canopus Alpha Car							A9II		   74			 -0.72  -2.5 Rigil Kentaurus Alpha Cen					G2V + K1V	  4.3			-0.27  4.4  Arcturus Alpha Boo						   K1.5IIIp	   34			 -0.04  0.2  Vega Alpha Lyr							   A0Va		   25			 0.03   0.6  Capella Alpha Aur							G6III + G2III  41			 0.08   0.4  Rigel Beta Ori							   B81ae		  ~1400		  0.12   -8.1 Procyon Alpha CMi							F5IV-V		 11.4		   0.38   2.6  Achernar Alpha Eri						   B3Vnp		  69			 0.46   -1.3 

 

Now supposed we wanted to check the numbers in this chart for accuracy. We can use the magnitudes to make our own distance calculation using the formula:

d = 3.26 10^(.2 (a - v + 5))

and compare this with the distance listed in the chart.

 

First we program a function in lisp to do this calculation.

(defun dist (v a)

(* 3.26 (expt 10.0 (* .2 (- v a -5)))))

dist

 

Next I insert "(dist " before the third column using paste (control y), and then I add an end parentheses ")" at the end of each line to get this

 

Sun										  G2V			-			  (dist -26.72 4.8  )Sirius Alpha CMa							 A1Vm		   8.6			(dist -1.46  1.4  )Canopus Alpha Car							A9II		   74			 (dist -0.72  -2.5 )Rigil Kentaurus Alpha Cen					G2V + K1V	  4.3			(dist -0.27  4.4  )Arcturus Alpha Boo						   K1.5IIIp	   34			 (dist -0.04  0.2  )Vega Alpha Lyr							   A0Va		   25			 (dist 0.03   0.6  )Capella Alpha Aur							G6III + G2III  41			 (dist 0.08   0.4  )Rigel Beta Ori							   B81ae		  ~1400		  (dist 0.12   -8.1 )Procyon Alpha CMi							F5IV-V		 11.4		   (dist 0.38   2.6  )Achernar Alpha Eri						   B3Vnp		  69			 (dist 0.46   -1.3 )

 

So now when I go the the end of each line and press control j I get

 

Sun										  G2V			-			  (dist -26.72 4.8  )1.6188909679280947e-005Sirius Alpha CMa							 A1Vm		   8.6			(dist -1.46  1.4  )8.734088738910044Canopus Alpha Car							A9II		   74			 (dist -0.72  -2.5 )73.9975941714126Rigil Kentaurus Alpha Cen					G2V + K1V	  4.3			(dist -0.27  4.4  )3.7950508558782015Arcturus Alpha Boo						   K1.5IIIp	   34			 (dist -0.04  0.2  )29.188891356916752Vega Alpha Lyr							   A0Va		   25			 (dist 0.03   0.6  )25.073652353343473Capella Alpha Aur							G6III + G2III  41			 (dist 0.08   0.4  )28.133100657203222Rigel Beta Ori							   B81ae		  ~1400		  (dist 0.12   -8.1 )1436.208855031364Procyon Alpha CMi							F5IV-V		 11.4		   (dist 0.38   2.6  )11.727828326077196Achernar Alpha Eri						   B3Vnp		  69			 (dist 0.46   -1.3 )73.31918015024647

 

If you look at the results above you will see something than I observed years ago, the data found in charts like this on the internet are not always very consistent. Capella is the worst here, comparing 28.133 light years to 41 light years we see this is off by more than 45%. Since the result for the sun has no comparison, lets multiply by the number of seconds in a year:

(* 60.0 60.0 24.0 365.25)

31557600.0

 

to get the distance to the sun in light seconds

 

(* 31557600.0 1.6188909679280923e-005)

510.8831360948757

 

which we can compare to the usual value of 499 light seconds.

 

Now lets go back to the topic of emacs lisp and cover some of the usual programing basics for this language in a quick summary, just in case you need them.

 

To set the value of a variable for use in a program you can use the setq operation.

 

(setq i 0)

0

 

For temporary variables within a program you can use the let operation. The following sets the variables a, b, and c to values which are used in each of the operations inside the let.

 

(let ((a 1.3) (b (log 2)) (c (log 10)))

(+ a b c)

(- (* a b c) (* a B) (* a c)))

-1.819612480849552

 

Notice that only the result of the final calculation is displayed. To display something else during the running of a program you can use the print operation.

 

(let ((a 1.3) (b (log 2)) (c (log 10)))

(print (+ a b c ))

(- (* a b c) (* a B) (* a c)))

 

4.295732273553991

-1.819612480849552

 

Since the let operation also lets you combine a series of calculations into a single program, you can use the let operation with an empty list of assignments just so you can take advantage of this feature. But rembember that only the result of the last calculation will be displayed unless you use the print command as follows.

 

(let ()

(print (* 2 3 4))

(print (* 3 4 5))

(print (* 4 5 6))

(* 5 6 7))

 

24

 

60

 

120

210

 

Logical testing operations like < = > <= and >= are also available. The following computes (log 2) and (log 10) and tests to see if the first is less than the second.

 

(< (log 2) (log 10))

t

 

Here it tests to see if log 2 is greater than log 10.

 

(> (log 2) (log 10))

nil

 

Notice that these testing operations display "t" for true and "nil" for false

 

The if operation uses these testing operations like this:

 

(if (< (log 2) (log 10))

(sin 2)

(sin 10))

0.9092974268256817

 

The if lisp operation takes three arguements, the first is the test, the second is the program which is run or value which is returned if the test returns true (t) and the third is the program that runs or value which is returned if the test is false (nil). So in the above example, only the first program calculating the sine of 2 is performed and displayed because the test evaluates to true.

 

After seting a few variables we can use the while operation for a loop to calculate the first five factorials. The first argument of the while operation is also a test, but this is followed by any number of calculations all of which are performed repeatedly as long as the test evaluates to true. The variables can be set using the setq operations but since i and j are temporary variables it makes more sense to use a let operation and this will make re-running the program much easier.

 

(let ((i 0) (j 1))

(while (< i 5)

(setq i (+ i 1))

(setq j (* j i))

(print j))

(list j 'is i 'factorial))

 

1

 

2

 

6

 

24

 

120

(120 is 5 factorial)

 

 

But the more usual way to do a loop in the lisp programming language is with a recursion. A recursion is a function that calls itself. When you do this it is important to test the input to check whether it is time to stop calling itself or you get an infinite loop.

 

(defun fact (x)

(if (= x 1) x

(* x (fact (- x 1)))))

fact

 

This defines the factorial function so we can get any factorial up to 99! when the maximum number of recursions is reached.

 

(fact 5)

120

 

(fact 99.0)

9.33262154439441e+155

 

Notice that I used 99.0 rather than 99. This was to make lisp use floating point arithmetic to avoid exceeding the maximum sized integer allowed.

 

Now perhaps I should mention that lisp was specifically designed to handle lists and in fact the name lisp comes from "list processing". A list is a series of space separated items inside parentheses. So for example a lisp program is itself a list. There are a number of operation in lisp used to create, combine, and extract portions of lists.

 

The list operation combines a series of arguments into a list

(list 1 2 3)

(1 2 3)

 

The cons operation appends an item to the front of a list. The single quotation mark is used in front of a list to prevent it from being evaluated like a program.

 

(cons 1 '(2 3))

(1 2 3)

 

car extracts the item at the beginning of a list.

 

(car '(1 2 3))

1

 

cdr extracts the list that remains when the first item is removed.

 

(cdr '(1 2 3))

(2 3)

 

cadr extracts the item second item of a list and it is called cadr because it is the same as the successive operations of cdr then car.

 

(cadr '(1 2 3))

2

 

(car (cdr '(1 2 3)))

2

 

cddr extract the the list that remains when the first two times are removed and it is called cddr because it is the same as the successive operation of cdr and cdr again.

 

(cddr '(1 2 3))

(3)

 

If a list is a program you can use the eval operation to run it.

 

(eval '(+ 1 2))

3

 

Here, for example, is a function that takes a list of programs and runs them to create a list of results. null tests a list to see if it is empty '() and nil is another way of representing the empty list.

 

(defun evalist (x)

(if (null x) nil

(cons (eval (car x)) (evalist (cdr x)))))

evalist

 

Now lets try this function out.

 

(evalist '((+ 1 2) (- 1 2) (* 1 2)))

(3 -1 2)

 

Now the whole emacs text editor is really a lisp interpreter and all of the text editing commands are lisp operations.

 

So if you press control x control e at the end of the following program it will actually move the cursor to the second line of the file that is loaded into emacs.

 

(goto-line 2)

 

To play around with this it would be more convenient to use two seperate windows in emacs (created using the split-window operation or control x 2). One with the file to edit in one window and your lisp programs in the other.

 

The following program will goto the begining of the file in the other window and then find every # character and ask you if you want it replaced by a % character.

 

(let ()

(other-window 1)

(goto-line 0)

(query-replace "#" "%"))

 

For more details on emacs lisp and a more careful explanation of the operations see http://forums.xisto.com/no_longer_exists/

 

There is also a detailed manual at http://forums.xisto.com/no_longer_exists/

Edited by mitchellmckain (see edit history)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.