Generating randoms numbers in a certain range for common lisp - random

I'm doing some homework and for one part I have to generate random numbers in the range 10 - 80. I know (random 80) will return a number less than 80 but how do I get it to get the numbers to be above 10 as well?

Hint: (+ 1 (random 80)) will give you a number between 1 and 80 inclusive.

This code will give you random numbers from 10 to 80:
(+ 10 (random 71))
even better, try this general formula:
(defun random-from-range (start end)
(+ start (random (+ 1 (- end start)))))

Related

Built in Binary Conversion in Scheme/Lisp

Is there a built in binary to decimal conversion function in Scheme?
I've found the built in number->string conversion which can convert binary to decimal form.
However, the opposite string->number doesn't convert decimals to binary string like I'd thought.
Is there a built in function or would we have to define it?
The string->number function accepts an optional radix parameter:
(string->number "1001" 2)
==> 9
Binary and decimal are representations of numbers; numbers themselves are not binary or decimal.
number->string converts from a number (such as twelve) to a string (such as "12"), outputting the number's base 10 representation by default.
(It does not convert from binary to decimal - its name describes what it does.)
string->number converts from a string (such as "12") to a number (such as twelve), interpreting the string as the base 10 representation of a number by default.
(This function's name also describes what it does.)
You can pass a second argument to both functions for a different base representation (2,8,10, or 16).
To get a string with the binary representation of the number n, use (number->string n 2).
To get a number from a string s with its binary representation, use (string->number s 2).
Examples:
> (number->string 120)
"120"
> (string->number "120")
120
> (number->string 120 2)
"1111000"
> (string->number "1111000" 2)
120
> (number->string 120 16)
"78"
> (string->number "78" 16)
120
Common Lisp
As with Scheme, numbers does not have bases in Common Lisp as well, only their representations.
Visualizing a number in a base using write-to-string:
(write-to-string 10 :base 2)
; ==> "1010"
Reading a number represented in a certain base using parse-integer:
(parse-integer "1010" :radix 2)
; ==> 10
; ==> 4 (index where the parser terminated)
(parse-integer "1010.1" :radix 2)
; parse-integer: substring "1010.1" does not have integer syntax at position 4
(parse-integer "1010.1" :radix 2 :junk-allowed t)
; ==> 10
; ==> 4 (index where the parser terminated)
Alternatively you can use the reader/printer, however reading only works if the next token cannot be interpreted as a float:
(let ((*print-base* 2))
(prin1-to-string 10))
; ==> "1010"
(let ((*read-base* 2))
(read-from-string "1010"))
; ==> 10
; ==> 5
;; *read-base* ignored when interpreted as float
(let ((*read-base* 2))
(read-from-string "1010.1"))
; ==> 1010.1
; ==> 6
I assume global *print-base* and *read-base* is both ten.
read-from-string doesn't care if there is junk after the number so it behaves as (parse-integer "1010" :radix 2 :junk-allowed t)
As an added info on the read base doc. You can tell the reader for literals for base 2, 8 and 16 and arbitrary which overrides the dynamic setting:
#b1010 ; ==> 10 (base 2)
#o1010 ; ==> 520 (base 8)
#x1010 ; ==> 4112 (base 16)
#3r1010 ; ==> 30 (base 3)
#36rToBeOrNotToBe ; ==> 140613689159812836698 (base 36)

Parsing strings representing lists of integers and integer spans

I am looking for a function that parses integer lists in Emacs Lisp, along the lines of Perl's Set::IntSpan. I.e., I would like to be able to do something like this:
(parse-integer-list "1-3, 4, 8, 18-21")
⇒ (1 2 3 4 8 18 19 20 21)
Is there an elisp library somewhere for this?
The following does what you want:
(defun parse-integer-list (str)
"Parse string representing a range of integers into a list of integers."
(let (start ranges)
(while (string-match "\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?" str start)
(push
(apply 'number-sequence
(seq-map 'string-to-int
(seq-filter
'identity
(list (match-string 1 str) (match-string 2 str)))))
ranges)
(setq start (match-end 0)))
(nreverse (seq-mapcat 'nreverse ranges))))
The code loops over the incoming string searching for plain numbers or ranges of numbers. On each match it calls number-sequence with either just a number for a plain match or two numbers for a range match and pushes each resulting number sequence into a list. To account for push building the result backwards, at the end it reverses all ranges in the list, concatenates them, then reverses the result and returns it.
Calling parse-integer-list with your example input:
(parse-integer-list "1-3, 4, 8, 18-21")
produces:
(1 2 3 4 8 18 19 20 21)

Generate a random number, excluding a single number

I'm writing a Monty Hall simulator, and found the need to generate a number within a range, excluding a single number.
This seemed easy, so I naively wrote up:
(The g/... functions are part of my personal library. Their use should be fairly clear):
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [rand-n (g/random-int min-n max-n rand-gen)
rand-n' (if (= rand-n excluding-n) (inc rand-n) rand-n)]
(g/wrap rand-n' min-n (inc max-n))))
This generates a random number within the range, and if it equals the excluded number, adds one; wrapping if necessary. Of course this ended up giving the number after the excluded number twice the chance of being picked since it would be picked either if it or the excluded number are chosen. Sample output frequencies for a range of 0 to 10 (max exclusive), excluding 2:
([0 0.099882]
[1 0.100355]
[3 0.200025]
[4 0.099912]
[5 0.099672]
[6 0.099976]
[7 0.099539]
[8 0.100222]
[9 0.100417])
Then I read this answer, which seemed much simpler, and based on it, wrote up:
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [r1 (g/random-int min-n excluding-n rand-gen)
r2 (g/random-int (inc excluding-n) max-n rand-gen)]
(if (g/random-boolean rand-gen) r1 r2)))
Basically, it splits the range into 2 smaller ranges: from the min to the excluded number, and from excluded number + 1 to the max. It generates random number from these ranges, then randomly chooses one of them. Unfortunately though, as I noted under the answer, this gives skewed results unless both the partitions are of equal size. Sample output frequencies; same conditions as above:
([0 0.2499497]
[1 0.2500795]
[3 0.0715849]
[4 0.071297]
[5 0.0714366]
[6 0.0714362]
[7 0.0712715]
[8 0.0715285]
[9 0.0714161])
Note the numbers part of the smaller range before the excluded number are much more likely. To fix this, I'd have to skew it to pick numbers from the larger range more frequently, and really, I'm not proficient enough in maths in general to understand how to do that.
I looked at the accepted answer from the linked question, but to me, it seems like a version of my first attempt that accepts more than 1 number to exclude. I'd expect, against what the answerer claimed, that the numbers at the end of the exclusion range would be favored, since if a number is chosen that's within the excluded range, it just advances the number past the range.
Since this is going to be one of the most called functions in the simulation, I'd really like to avoid the "brute-force" method of looping while the generated number is excluded since the range will only have 3 numbers, so there's a 1/3 chance that it will need to try again each attempt.
Does anyone know of a simple algorithm to chose a random number from a continuous range, but exclude a single number?
To generate a number in the range [a, b] excluding c, simply generate a number in the range [a, b-1], and if the result is c then output b instead.
Just generate a lazy sequence and filter out items you don't want:
(let [ignore #{4 2}]
(frequencies
(take 2000
(remove ignore (repeatedly #(rand-int 5))))))
Advantage to the other approach of mapping to different new values: This function will also work with different discrete random number distributions.
If the size of the collection of acceptable answers is small, just put all values into a vector and use rand-nth:
http://clojuredocs.org/clojure.core/rand-nth
(def primes [ 2 3 5 7 11 13 17 19] )
(println (rand-nth primes))
(println (rand-nth primes))
(println (rand-nth primes))
~/clj > lein run
19
13
11
Update
If some of the values should include more than the others, just put them in the array of values more than once. The number of occurrances of each value determines its relative weight:
(def samples [ 1 2 2 3 3 3 4 4 4 4 ] )
(def weighted-samples
(repeatedly #(rand-nth samples)))
(println (take 22 weighted-samples))
;=> (3 4 2 4 3 2 2 1 4 4 3 3 3 2 3 4 4 4 2 4 4 4)
If we wanted any number from 1 to 5, but never 3, just do this:
(def samples [ 1 2 4 5 ] )
(def weighted-samples
(repeatedly #(rand-nth samples)))
(println (take 22 weighted-samples))
(1 5 5 5 5 2 2 4 2 5 4 4 5 2 4 4 4 2 1 2 4 1)
Just to show the implementation I wrote, here's what worked for me:
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [rand-n (g/random-int min-n (dec max-n) rand-gen)]
(if (= rand-n excluding-n)
(dec max-n)
rand-n)))
Which gives a nice even distribution:
([0 0.111502]
[1 0.110738]
[3 0.111266]
[4 0.110976]
[5 0.111162]
[6 0.111266]
[7 0.111093]
[8 0.110815]
[9 0.111182])
Just to make Alan Malloy's answer explicit:
(defn rand-int-range-excluding [from to without]
(let [n (+ from (rand-int (dec (- to from))))]
(if (= n without)
(dec to)
n)))
(->> #(rand-int-range-excluding 5 10 8)
repeatedly
(take 100)
frequencies)
;{6 28, 9 22, 5 29, 7 21}
No votes required :).

Scheme add columns in a matrix

I am trying to write a function that takes a matrix (represented as a list of lists) and adds the elements down the columns and returns a vector (represented as a list):
Example:
(define sample
'((2 6 0 4)
(7 5 1 4)
(6 0 2 2)))
should return '(15 11 3 10).
I was trying to use the (list-ref) function twice to obtain the first element of each column with no luck. I am trying something like:
(map (lambda (matrix) ((list-ref (list-ref matrix 0) 0)) (+ matrix))
The solution is simple if we forget about the indexes and think about higher-order procedures, try this:
(define sample
'((2 6 0 4)
(7 5 1 4)
(6 0 2 2)))
(apply map + sample)
=> '(15 11 3 10)
Explanation: map can take multiple lists as arguments. If we apply it to sample (which is a list of lists) and pass + as the procedure to do the mapping, it'll take one element from each list in turn and add them, producing a list with the results - effectively, adding all the columns in the matrix.

Scheme Understanding

I am supposed to write a scheme function (digit-count n) that accepts a positive integer n and evaluates to the number of digits of n that are 6, 4, or 9.
I am having trouble understanding what exactly I am supposed to do, I am confused about the "digits of n that are 6, 4 or 9", what does this mean?
This is just an interpretation question, but I would say that you would take the decimal representation of a number, and count the total number of digits that are 6, 4, or 9. For example:
100 --> 0
4 --> 1
469 --> 3
444 --> 3
Get it now?
One interpretation - example:
Given 678799391, the number of digits would be 0 for 4, 1 for 6 and 3 for 9. The sum of the occurences would be 0 + 1 + 3 = 4.
Convert the whole number to a list and check each one individually.
(define (number->list x)
(string->list (number->string x))
(define (6-4-or-9 x) (cond ((= x 6) true)) ((= x 4) true)) ((= x 9) true))))
(define (count-6-4-9 x) (cond ((6-4-or-9 (car (number->list x)))).......
I'm sure you can see where that's going. It's pretty crude, and I'm not sure it's really idiomatic, but it should work.
The idea is is that you convert the number to a list, check to first digit, if it's six, four or nine, recursively call the procedure on the cdr of the number list converted back to a string + 1...
If you are not using lists, you can work with modulo % of 10 and dividing whole numbers / with 10.
Below is the recursive solution :
(define (digits n)
(if(not (< n 1)) (+ 1 (digits (/ n 10))) 0))
First, we must understand what the question is asking: It is asking you to write a procedure that counts the number of times the numbers 4, 6, or 9 show up in another inputted number. For instance, inputting 10345 should return 1. Let's see why:
The digits of 10345 are 1, 0, 3, 4, and 5. We have to ask, "How many times do 4, 6, or 9 show up?" Well, there are no 6's or 9's in 10345. However, there is one 4. Therefore, the procedure should return 1.
Another example: (digit-count 14289)
Let's break it up like we did before. The digits of 14289 are 1, 4, 2, 8, and 9. There are no 6's. There are, however, 1's and 9's. How many? There is one 1 and one 9. Since there are two (total) of the desired digits present (desired digits are 4, 6, and 9), (digit-count 14289) should return 2.
Some more examples:
(digit-count 144) --> 2 (there are two 4's)
(digit-count 1) --> 0 (there are no 4's, 6's, or 9's)
(digit-count 1262) --> 1 (there is one 6)
Now, let's start defining. We can take advantage of the appearances function, which takes two inputs and returns how many times the first input appears in the second.
For example: (appearances 'a 'amsterdam) returns 2 because there are two a's in amsterdam.
Using appearances, here is our definition (finally!):
(define (count469 num)
(+ (appearances 4 num)
(appearances 6 num)
(appearances 9 num)))
This function returns the sum of the appearances of 4, the appearances of 6, and the appearances of 9. Please feel free to reply with any feedback or questions!

Resources