I'm trying to write a binary output function that does two's complements as well. It sort of works, but it feels like hard work - is there an easier way?
(define (binary n (width 24) , temp)
(print (format {%6d } n))
(set 'temp '() 'x n)
(if (< n 0) (inc 'x))
(until (= x 0)
(push (string (% (abs x) 2)) temp)
(set 'x (/ x 2)))
(set 'result (format (string {%0} width {s}) (join temp)))
(and
(< n 0)
(replace "1" result "x")
(replace "0" result "1")
(replace "x" result "0"))
(println result))
(for (i -10 10)
(binary i 16))
-10 1111111111110110
-9 1111111111110111
-8 1111111111111000
-7 1111111111111001
-6 1111111111111010
-5 1111111111111011
-4 1111111111111100
-3 1111111111111101
-2 1111111111111110
-1 1111111111111111
0 0000000000000000
1 0000000000000001
2 0000000000000010
3 0000000000000011
4 0000000000000100
5 0000000000000101
6 0000000000000110
7 0000000000000111
8 0000000000001000
9 0000000000001001
10 0000000000001010
It gets easier if you discover the bits in the number directly and then shift them out one by one:
(define (binary n (width 24) , temp)
(dotimes (i width)
(push (& n 1) temp)
(set 'n (>> n)))
(join (map string temp)))
(for (n -10 10) (println (format "%6d %s" n (binary n 16))))
-10 1111111111110110
-9 1111111111110111
-8 1111111111111000
-7 1111111111111001
-6 1111111111111010
-5 1111111111111011
-4 1111111111111100
-3 1111111111111101
-2 1111111111111110
-1 1111111111111111
0 0000000000000000
1 0000000000000001
2 0000000000000010
3 0000000000000011
4 0000000000000100
5 0000000000000101
6 0000000000000110
7 0000000000000111
8 0000000000001000
9 0000000000001001
10 0000000000001010
Lutz
ps: exchanged (if (= 1 (& n 0x1)) 1 0) for (& n 1) after riickyboy's remark
Very nice - thanks!
Very nice Lutz.
BTW, you can replace '(if (= 1 (& n 0x1)) 1 0)' with '(& n 0x1)' in the body of 'binary' and it will work the same.
I also liked how Lutz separated the 'print(ln)'ing of the result with the building of the result string. I like this design. I too try to avoid "embedded prints" in "building" functions, because I have always seemed to find a use for the result string either before, or instead of, printing it. Good job!
--Rick
Yes, I must plead guilty to sometimes putting print statements in my functions! It certainly doesn't promote the building-block approach. But occasionally it provides a bit of clarity - when writing tutorials, for example - if you use a function that has an all-in-one "apply-process-report" action. I'm writing this as we speak:
(binary (^ 4 5))
1 000000000000000000000001
(binary (| 4 5))
5 000000000000000000000101
which I quite like.
My other excuse is that I use a text editor too much... ;-)
Most try their programs interactively, loading from the commandlione and then exeuting the function. The editor is open in a different window.
newLISP v.9.0.4 on OSX UTF-8, execute 'newlisp -h' for more info.
> (load "binary")
(lambda (n (width 24) , temp)
(dotimes (i width)
(push (& n 1) temp)
(set 'n (>> n)))
(join (map string temp)))
> (binary 10)
"000000000000000000001010"
>
The 'load' command then comes back with the return value of the last evaluation in the file, which was a 'define' statement returning a the lambda expression.
You then edit the file, save it and do: cursor-up-up <enter> in the newLISP terminal to get the (load "binary") line back. Then cursor-up-up <enter> again to execute: (binary 10).
Sometimes I do:
>!vi binary
; or on Mac OS X
>!open -e binary
and call up my editor (vi) inside the same newLISP terminal window. When I quit the editor I am back in the newLISP command line. Another advantage of this approach is that inside the newLISP terminal the tab-key expands to file names in the same directory so hitting tab after: >!vi bin will expand the bin to binary.
Lutz
I am using text editor and newLISP-tk:
text editor: modify & save
newLISP-tk: load/reload
by typing interactively (binary ...) in newLISP-tk, I get results without printing them.
------
My text editor is PSPad (Win32 only)
http://www.pspad.com/
Lutz, feel free to post a syntax highlighting file for PSPad on newlisp.org. I put the file here:
http://www.intricatevisions.com/download/newLISP.ini
Fanda