please help decipher this lisp extract - lisp

(let ((g (* 2 (or (gethash word good) 0)))
(b (or (gethash word bad) 0)))
(unless (< (+ g b) 5)
(max .01
(min .99 (float (/ (min 1 (/ b nbad))
(+ (min 1 (/ g ngood))
(min 1 (/ b nbad)))))))))

What is the problem? It is almost plain english:
Let g be the value of word in the hashtable good (or 0 if not existent there) times 2
(let ((g (* 2 (or (gethash word good) 0)))
and b the value of word in the hashtable bad (or 0 if not existent there).
(b (or (gethash word bad) 0)))
With this in mind, and under the presumption that the sum of g and b is not smaller than 5
(unless (< (+ g b) 5)
return the maximum of either 0.01 or
(max .01
the minimum of either 0.99 or
(min .99
b/nbad divided by the sum of b/nbad and g/ngood (as a float value, and those individual quotients should be at most 1).
(float (/ (min 1 (/ b nbad))
(+ (min 1 (/ g ngood))
(min 1 (/ b nbad)))))))))

Looks like it is trying to calculate a score based on the presence of word in the the hash tables good and bad.
If the word does not exist in a hash table it is given a value of 0, otherwise if it exists in the good table it is weighted by 2 (doubled).
If the score is less than 5 calculate the score (portion below unless) as follows:
score = min(1, b/nbad) / (min(1, g/ngood) + min(1, b/nbad))
max(0.01, min(0.99, score))
I'm not sure what ngood and nbad are but then n indicates to me they are probably counts. It also looks like the code is keeps the calculated score below 5. It also looks like in the score calculation the denominator will be kept to a maximum 2 keep the lower bound of the score to 0.5.
Based on the tags you've used, I would guess (and it is just a guess) that it is trying to calculate a weighting for word based on some kind of frequency(?) counting of the word in good versus bad email.

Related

How to display first N natural numbers, knowing the divisors in Lisp

Display first N natural numbers, the divisors of which are only 2, 3 and 7.
I wrote something like that. I am a beginner in Lisp. Thank you!
defvar x 1
(defun numbers(n)
if(mod x 2 )
(loop for x from 1 to n
do(print x)
)
)
print(numbers())
Because I just had some time, you could have a look at this. Might not be the perfect solution but should be a good starting point for a beginner. Check out the books in the info tab to get into the syntax etc.
(defun divisible-by (n m)
"Returns T if N is evenly divisible by M."
(zerop (mod n m)))
(defun numbers (n)
"Print all number upto N which are divisible by 2, 3 and 7."
(loop
for i from 1 upto N
if (and (divisible-by i 2) (divisible-by i 3) (divisible-by i 7))
do (format t "~D~%" i)))

Building a random list

I am trying to write a function that takes in the length of a list and a maximum number value and returns a list that is the length given with numbers between 1 and the given max randomly.
so far I have
(define (randomlist n max)
(cond
[(= n 0)empty]
[else
(cons (build-list n (random 1 max))
(randomlist max (- n 1)))]))
I get an error when I run this and was wondering if anybody could help me out.
One can also use for/list to combine loop and list formation:
(define (randomlist n mx)
(for/list ((i n))
(add1 (random mx))))
Testing:
(randomlist 5 10)
Output:
'(5 9 10 4 7)
(random numbers, hence output is very likely to be different each time).
There are several bugs in your code:
It's a bad idea to call a parameter max, that clashes with a built-in procedure. So I renamed it to mx.
There's absolutely no reason to use build-list, that's not how we build an output list, just cons one element with the rest.
random receives zero or one parameters, not two. The single-parameter version returns an integer in the range 0..n-1, hence we have to add 1 to the result to be in the range 1..n.
You switched the order of the parameters when recursively calling randomlist.
This should take care of the problems:
(define (randomlist n mx)
(cond
[(= n 0) empty]
[else
(cons (+ 1 (random mx))
(randomlist (- n 1) mx))]))
It works as expected:
(randomlist 5 10)
=> '(10 7 1 4 8) ; results will vary, obviously

Sum numbers that are positive which is less than n

(defun sum (n)
(if (n<0) 0 n-1) ;; if n<0, add 0. Else add the next smallest.
(sum (n-1)))
So far I come out with something like this but I am not sure how do I declare a variable to store the sum that I would like to return.
Note that you are implementing 1+2+...+m for m = n-1, which admits a simple formula:
(lambda (n)
;; You could inject n-1 on the formula to get n.(n-1)/2
;; (like in Vatine's answer), but here I just decrement
;; the input to show how to modify the local variable
;; and reuse the formula linked above to sum up-to m.
(decf n)
(if (minusp n)
0
(/ (* n (1+ n)) 2)))
An iterative version would work too, there is no need go recursive when doing simple loops:
(lambda (n) (loop :for x :below n :sum x))
Regarding your code:
Space matters1: n<0 is read as a symbol of name "N<0" (upcased by default). The same goes for n-1 which is a symbol named "N-1".
(n<0) will attempt to run the function named n<0. The same goes for (n-1).
Comparison: you can use (minusp n) or (< n 0).
Decrement: you can use (1- n) or (- n 1).
If what you wrote was correctly written, like this:
(defun sum (n)
(if (< n 0) 0 (- n 1))
(sum (- n 1)))
... there would still be issues:
You expect your (n-1) to actually decrement n but here the if only compute a value without doing side-effects.
You unconditionally call (sum (n-1)), which means: infinite recursion. The value returned by the preceding if is always ignored.
1: For details, look at constituent and terminating characters: 2.1.4 Character Syntax Types
Edit: zerop > minusp to check for negative numbers, fixed to fit OPs question
Was some time ago I used Lisp but if I recall right the last evaluation gets returned. A recursive solution to your problem would look like this:
(defun sum (n)
(if (<= n 0) 0 ;;if n is less or equal than 0 return 0
(+ (- n 1) (sum (- n 1))))) ;; else add (n-1) to sum of (n-1)
In Lisp, all comparator functions are just that, functions, so it needs to be (< n 0) and (- n 1) (or, more succinct, (1- n)).
You don't need to keep an intermediate value, you can simply add things up as you go. However, this is complicated by the fact that you are summing to "less than n", not "to n", so you need to use a helper function, if you want to do this recursively.
Even better, if you peruse the standard (easily available on-line, as the Common Lisp HyperSpec, you will sooner or later come across the chapter on iteration, where the loop facility does everything you want.
So if I needed to do this, I would do one of:
(defun my-sum (n)
(/ (* n (1- n)) 2))
or
(defun my-sum (n)
(loop for i below n
sum i))
If I absolutely needed to make it recursive, I would use something like:
(defun my-sum (n)
(labels ((sum-inner (i)
(if (< i 1)
0
(+ i (sum-inner (1- i))))))
(sum-inner (1- n))))
This is (almost) identical to defining a global function called sum-inner, which may be preferable for debugging purposes. However, since it is very unlikely that sum-inner would have any other use, I made it local.

How to sum all numbers that are divisible by 3 or 5 below 1000 in Lisp?

I started programming in Common Lisp yesterday. Now I want to find the sum of all the multiples of 3 or 5 below 1000. I came up with:
(loop for n from 1 to 1000 when
(or
(eq (mod n 5) 0)
(eq (mod n 3) 0))
(sum n)))
I know that the looping part works (loop for n from 1 to 1000 sum n) to sum the first 1000 numbers. I know that the ((eq (mod n 5) 0) (mod n 3) 0)) parts works. And I know that (or (eq (mod n 5) 0) (eq (mod n 3) 0)) works. So it looks like a robust program to me, but when I run it I get the error:
1=(SUM N) found where keyword expected getting LOOP clause after WHEN current LOOP context: WHEN (OR (EQ (MOD 1000 5) 0)
(EQ (MOD 1000 3) 0))
1#. [Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]
I suspect something is wrong with the (sum n) after the or-statement. But I do not know why that is or how I can solve it. Can someone help me out and get my first Lisp program to work?
sum n, not (sum n)
Don't put sum n in parentheses. The loop macro is its own domain specific language with its own grammar. With it, you'd (loop for ... sum n). The grammar is given in HyperSpec entry on loop in this production:
numeric-accumulation::= {count | counting | sum | summing | }
maximize | maximizing | minimize | minimizing {form | it}
[into simple-var] [type-spec]
If it sounds any better to, you can also write (loop for … summing n). That might read more like a natural English sentence.
=, eql, or zerop, but not eq
It's good practice to get into looking up functions, macros, etc., in the HyperSpec. As Rainer Joswig points out, you shouldn't use eq for comparing numbers. Why? Let's look it up in the HyperSpec. The examples include:
(eq 3 3)
=> true
OR=> false
(eq 3 3.0) => false
(eq 3.0 3.0)
=> true
OR=> false
(eq #c(3 -4) #c(3 -4))
=> true
OR=> false
and the Notes section says (emphasis added):
Objects that appear the same when printed are not necessarily eq to
each other. Symbols that print the same usually are eq to each other
because of the use of the intern function. However, numbers with the
same value need not be eq, and two similar lists are usually not
identical.
An implementation is permitted to make "copies" of characters and
numbers at any time. The effect is that Common Lisp makes no guarantee
that eq is true even when both its arguments are "the same thing" if
that thing is a character or number.
For numbers you need something else. = is a good general numeric comparison, although it does more work here than what you need, because it can compare numbers of different types. E.g., (= 5 5.0) is true. Since you're only concerned about 0, you could use zerop, but that will still do a bit more work than you need, since it will check other numeric types as well. E.g., (zerop #c(0.0 0.0)) is true. In this case, since (mod n …) will be giving you an integer, you can use eql:
The value of eql is true of two objects, x and y, in the folowing
cases:
If x and y are eq.
If x and y are both numbers of the same type and the same value.
If they are both characters that represent the same character.
Thus, you can use (or (eql (mod n 3) 0) (eql (mod n 5) 0)).
Other ways of doing this
Now, your question was about a particular piece of loop syntax, and there were some points to be made about equality operators. However, since some of the other answers have looked at other ways to do this, I think it's worth pointing out that there are much more efficient ways to do this. First, let's look at a way to sum up all the multiples of some number beneath a given limit. E.g., for the number 3 and the inclusive limit 26, we have the sum
?
= 3 + 6 + 9 + 12 + 15 + 18 + 21 + 24
= (3 + 24) + (6 + 21) + (9 + 18) + (12 + 15)
= 27 + 27 + 27 + 27
In general, if you try with a few different numbers, you can work out that for an inclusive limit l and a number n, you'll be adding up pairs of numbers, with an optional half pair if there's a odd number of multiples of n that are less than l. I'm not going to work out the whole derivation, but you can end up with
(defun sum-of-multiples-below-inclusive (limit divisor)
(multiple-value-bind (quotient remainder)
(floor limit divisor)
(let ((pair (+ (- limit remainder) divisor)))
(multiple-value-bind (npairs half-pair)
(floor quotient 2)
(+ (* npairs pair)
(if (oddp half-pair)
(floor pair 2)
0))))))
Then, to find out the sum of the number of multiples less than a given number, you can just substract one from limit:
(defun sum-of-multiples-below (limit divisor)
(sum-of-multiples-below (1- limit) divisor))
Then, to expand to your case, where there are multiple divisors, you'll need to add some of these numbers, and then subtract out the ones that are getting counted twice. E.g., in your case:
(+ (sum-of-multiples-below 1000 3)
(sum-of-multiples-below 1000 5)
(- (sum-of-multiples-below 1000 15)))
;=> 233168
(loop for i from 1 below 1000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i)
;=> 233168
Now, using time naively can lead to misleading results, but SBCL compiles forms before it evaluates them, so this isn't too terrible. This is a very, very, small micro-benchmark, but take a look at the number of cycles used in each form:
(time (+ (sum-of-multiples-below 1000 3)
(sum-of-multiples-below 1000 5)
(- (sum-of-multiples-below 1000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
11,327 processor cycles
0 bytes consed
(time (loop for i from 1 below 1000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
183,843 processor cycles
0 bytes consed
Using the closed form is much faster. The different is more pronounced if we use a higher limit. Let's look at 100,000:
(time (+ (sum-of-multiples-below 100000 3)
(sum-of-multiples-below 100000 5)
(- (sum-of-multiples-below 100000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
13,378 processor cycles
0 bytes consed
(time (loop for i from 1 below 100000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.007 seconds of real time
0.004000 seconds of total run time (0.004000 user, 0.000000 system)
57.14% CPU
18,641,205 processor cycles
0 bytes consed
For 10,000,000 the numbers are even more staggering:
(time (+ (sum-of-multiples-below 10000000 3)
(sum-of-multiples-below 10000000 5)
(- (sum-of-multiples-below 10000000 15))))
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
13,797 processor cycles
0 bytes consed
(time (loop for i from 1 below 10000000
when (or (eql 0 (mod i 3))
(eql 0 (mod i 5)))
sum i))
Evaluation took:
0.712 seconds of real time
0.712044 seconds of total run time (0.712044 user, 0.000000 system)
100.00% CPU
1,916,513,379 processor cycles
0 bytes consed
Some of these Project Euler problems are pretty interesting. Some of them have some pretty straightforward naïve solutions that work for small inputs, but don't scale well at all.
I would format the code like this:
(loop for n from 1 below 1000
when (or (zerop (mod n 3))
(zerop (mod n 5)))
sum n))
one line less
when at the start of a line
no need to have or alone on a line
clauses in LOOP don't have parentheses
use below
This kind of Loop macro goes back to the early 70s to Interlisp, long before Common Lisp existed.
Here is a another solution without loop
(defun sum-to-thousand (count result)
(cond ((> count 1000) result)
((= (mod count 3) 0) (sum-to-thousand (+ count 1) (+ count result)))
((= (mod count 5) 0) (sum-to-thousand (+ count 1) (+ count result)))
(t (sum-to-thousand (+ count 1) result))))
May I propose more "lispier" variant:
CL-USER> (defun my-sum (&key (from 1) to dividers (sum 0))
(if (>= from to)
sum
(my-sum :from (1+ from)
:to to
:dividers dividers
:sum (if (some (lambda (x) (zerop (mod from x))) dividers)
(+ sum from)
sum))))
MY-SUM
CL-USER> (my-sum :to 1000 :dividers '(3 5))
233168

Lisp, sub total of a numbers in a nested list

i have a problem that i just cant work out,
the user enters a list ie
(total-cost
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51)))
i need to add the number on the end together and then return the result
my current code returns the code after each addition. and also throws a error about unexpected type
(defun total-cost (list)
(loop with sum = 0
for x in list
collect (setf sum (+ sum (last x)))
)
)
Error: (0.01)' is not of the expected typeNUMBER'
Any help is appreciated
Thanks Dale
Using LOOP:
CL-USER 19 > (loop for (nil nil number) in '((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
sum number)
6.72
REDUCE is another option:
CL-USER 20 > (reduce '+
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
:key 'third)
6.72
Loop has a keyword sum for summing so you don't have to have an explicit variable nor use setf:
(defun total-cost (list)
(loop for x in list sum (third x)))
As Chris said, use (car (last x)) if the number you're looking for is always the last one. Or you can use (third x) as in my example if it's always the third one.
Also, note that the use of collectis wrong if your aim is to return the sum only; your example (corrected) returns
(0.01 0.11 4.21 6.7200003)
whereas mine returns
6.7200003
Note that if you want so escape the rounding errors as much as possible you need to use an exponent marker to make them double-floats for example:
(total-cost '((anItem 2 0.01D0)
(item 3 0.10D0)
(anotherItem 4 4.10D0)
(item 5 2.51D0)))
=> 6.72D0
last returns the last cons cell in the list, not its value. You need to use (car (last x)) instead.
Just in case you want the code to give you a precise result rather then being short:
(defun kahan-sum (floats)
(loop
:with sum := 0.0 :and error := 0.0
:for float :in floats
:for epsilon := (- float error)
:for corrected-sum := (+ sum epsilon) :do
(setf error (- corrected-sum sum epsilon) sum corrected-sum)
:finally (return sum)))
(defun naive-sum (floats) (loop :for float :in floats :sum float))
(let ((floats (loop :repeat 1000 :collect (- (random 1000000.0) 1000000.0))))
(format t "~&naive sum: ~f, kahan sum: ~f" (naive-sum floats) (kahan-sum floats)))
;; naive sum: -498127420.0, kahan sum: -498127600.0
Read more about why it works like this here: http://en.wikipedia.org/wiki/Kahan_summation_algorithm
Coming late to the party... How about a little lisping instead of looping? ;-)
(defun sum-3rd (xs)
(let ((sum 0))
(dolist (x xs sum)
(incf sum (nth 2 x)))))