Built in Binary Conversion in Scheme/Lisp - scheme

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)

Related

unpacking binary file via octets->string->unpack fails: signed int `#(243 0)` is illegal UTF8

I am parsing a binary file (nifti) with a mix of chars, floats, ints, and shorts (using the PDL::IO::Nifti cpan module as reference).
I am having some luck parsing sequences of octets to a string so they can be passed to cl-pack:unpack. This is convoluted but convenient for porting using the perl module as reference.
This strategy fails on reading #(243 0) as binary
(setf my-problem (make-array 2
:element-type '(unsigned-byte 8)
:initial-contents #(243 0)))
(babel:octets-to-string my-problem)
Illegal :UTF-8 character starting at position 0
and, when trying to read the file as char*
the octet sequence #(243 0 1 0) cannot be decoded.
I'm hoping there is a simple encoding issue I haven't figured out. Trying to go in the reverse direction (packing 243 and getting octets) gives a vector of length 3 for what I expect to be 2.
(babel:string-to-octets (cl-pack:pack "s" 243))
; yields #(195 179 0) expect #(243 0)
Full context
;; can read up to position 40. at which we expect 8 signed ints.
;; 4th int is value "243" but octet cannot be parsed
(setq fid-bin (open "test.nii" :direction :input :element-type 'unsigned-byte))
(file-position fid-bin 40)
(setf seq (make-array (* 2 8) :element-type '(unsigned-byte 8)))
(read-sequence seq fid-bin)
; seq: #(3 0 0 1 44 1 243 0 1 0 1 0 1 0 1 0)
(babel:octets-to-string seq) ; Illegal :UTF-8 character starting at position 6.
(sb-ext:octets-to-string seq) ; Illegal ....
;; first 3 are as expected
(cl-pack:unpack "s3" (babel:octets-to-string (subseq seq 0 6)))
; 3 256 300
(setf my-problem (subseq seq 6 8)) ; #(243 0)
(babel:octets-to-string my-problem) ; Illegal :UTF-8 character starting at position 0.
;; checking the reverse direction
;; 243 gets represented as 3 bytes!?
(babel:string-to-octets (cl-pack:pack "s3" 3 256 300)) ; #(3 0 0 1 44 1)
(babel:string-to-octets (cl-pack:pack "s4" 3 256 300 243)) ; #(3 0 0 1 44 1 195 179 0)
(setq fid-str (open "test.nii" :direction :input))
(setf char-seq (make-array (* 2 8) :initial-element nil :element-type 'char*))
(file-position fid-str 40)
(read-sequence char-seq fid-str)
;; :UTF-8 stream decoding error on #<SB-SYS:FD-STREAM ....
;; the octet sequence #(243 0 1 0) cannot be decoded.
The perl equivalent
open my $f, "test.nii";
seek $f, 46, 0;
read $f,my $b, 2;
print(unpack "s", $b); # 243
The problem is that you are using functions which try to treat some sequence of octets as a representation of an encoding of a sequence of characters (or of some Unicode things: I think there are things other than characters in Unicode). In particular, in your case, the functions you are using are treating a sequence of octets as the UTF-8 encoding of some string. Well, not all sequences of octets are legal UTF-8 so the functions are, correctly, puking on an illegal sequence of octets.
But that's because you're not doing the right thing: what you want to do is to take a sequence of octets and make a string whose char-codes are those octets. You don't want to be doing with any silly encoding-big-characters-in-small-integers rubbish, because you will never see any big characters. You want something like these functions (both somewhat misnamed, since they aren't fussed about the whole octet thing unless you are).
(defun stringify-octets (octets &key
(element-type 'character)
(into (make-string (length octets)
:element-type element-type)))
;; Smash a sequence of octets into a string.
(map-into into #'code-char octets))
(defun octetify-string (string &key
(element-type `(integer 0 (,char-code-limit)))
(into (make-array (length string)
:element-type element-type)))
;; smash a string into an array of 'octets' (not actually octets)
(map-into into #'char-code string))
And now you can check everything works:
> (octetify-string (pack "s" 243))
#(243 0)
> (unpack "s" (stringify-octets (octetify-string (pack "s" 243))))
243
and so on. Given your example sequence:
> (unpack "s8" (stringify-octets #(3 0 0 1 44 1 243 0 1 0 1 0 1 0 1 0)))
3
256
300
243
1
1
1
1
A really much better approach would be to have the packing & unpacking functions simply handle sequences of octets. But I suspect that's a lost cause. An interim approach which is horrible but less horrible than converting sequences of octets to characters would be to read the file as text but with an external-format which does no translation at all. How to do that is implementation-dependent (but something based on latin-1 will be a good start).
It seems that the problem is indeed encoding-related:
CL-USER> (cl-pack:pack "s" 243)
"ó\0"
which is the same as the result of:
(babel:octets-to-string my-problem :encoding :iso-8859-1)

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)

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.

Generating randoms numbers in a certain range for common lisp

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)))))

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