two's complement and binary output

Started by cormullion, November 28, 2006, 02:14:22 AM

Previous topic - Next topic

cormullion

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


Lutz

#1
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

cormullion

#2
Very nice - thanks!

rickyboy

#3
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
(λx. x x) (λx. x x)

cormullion

#4
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... ;-)

Lutz

#5
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

Fanda

#6
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/">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">http://www.intricatevisions.com/download/newLISP.ini



Fanda