17

As part of my homework for discrete math I need to convert different decimal values, both positive and negative, to 8-bit binary representations using signed magnitude, 1's complement, and 2's complement. Could anyone suggest an elegant way to present my solutions?

An example of handwritten technique is available this

enter image description here

percusse
  • 157,807
beethree
  • 639

3 Answers3

32

In your initial question I thought you were looking at suggestions for ways of tabulating the bit patterns, something like the first couple of examples. But your edit indicated you wanted to display the working. Something like this might work for that, I just do the easy unsigned case as you showed, I leave the rest as you say it's homework:-)

enter image description here

\documentclass{article}

\newcommand\decbin[9]{%
\par\smallskip
\makebox[3cm][r]{$#1$\ }\fbox{#2}\,\fbox{#3}\,\fbox{#4}\,\fbox{#5}\,\fbox{#6}\,\fbox{#7}\,\fbox{#8}\,\fbox{#9}\par}


\def\unsignedbytecalc#1{%
\par\smallskip
\noindent$#1_{10}$\par
\smallskip
\gdef\result{}%
$\left.\begin{array}{r@{\quad}|c}\udbc{#1}\end{array}\right\}\result$\par}

\makeatletter

\def\udbc#1{%
\ifnum#1=\z@
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{2)\!\underline{\,#1}&\edef\r{\ifodd#1 1\else 0\fi}\r\xdef\result{\r\result}\\
\expandafter\udbc\expandafter{\the\numexpr(\ifodd#1 #1-1\else#1\fi)/2\relax}%
}}


\begin{document}

\decbin{13} 00001101
\decbin{54} 00110110

\unsignedbytecalc{156}

\end{document}
David Carlisle
  • 757,742
24

Update: I add at the end an illustration of the reverse process of base b to decimal conversion

I have not tried to do the upgoing arrow... I am sorry for all those @ which render the code barely readable (to me). I originally used \n, \m etc... but one always fears overwriting something in LaTeX.

The method uses an expandable loop inside a tabular, so as to get alignment on the right. No test is done on the input which should not be negative.

I do a little play with local and global assignments but maybe using one more count variable would give a more easily readable code. The point anyhow is that computations should not be done twice, despite the restricted scope due to the tabular cell.

When the base is $\leq 36$, the digits use the alphabet starting with $10 = A$.

The base is the optional argument. Please do not use 1...

\documentclass{article}
\usepackage[left=1cm, right=2cm, vmargin=1cm]{geometry}

% expandable loop (used to avoid scope problems in tabular cells with the
% standard \loop)
\def\boucle #1\repeat {#1\b@@cle {#1}\repeat \repeat }
\def\b@@cle #1{\repeat #1\b@@cle {#1}}

\makeatletter
\newcount\@nn
\newcount\@mm
\newcount\@base
\newcount\@baseminusone

% please do not use this at home
% #1 must be a counter name, not something expanding to a number.
\def\@arabalpha #1{\ifcase #10\or1\or2\or3\or4\or5\or6\or7\or8\or9\or 
A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M\or N\or O\or
P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z\fi}

\newcommand{\baseexpansion}[2][2]{% no negative numbers please!
\def\@digits{}%
\@base#1\relax \@baseminusone\@base\advance\@baseminusone-1
\@nn #2\relax  % this is the number to be written in base #1
%
\ifnum\@baseminusone<36
\def\onerow{#1\kern.1em\hbox{\vrule
   \vtop {\hbox{\ \the\@nn}\kern.3ex\hrule height.1ex }} &%
   \global\@mm\@nn \global\divide\@mm\@base 
   \multiply\@mm\@base \advance\@nn-\@mm 
   \the\@nn \xdef\@digits{\@arabalpha\@nn\@digits}}%
\else
\def\onerow{#1\kern.1em\hbox{\vrule
   \vtop {\hbox{\ \the\@nn}\kern.3ex\hrule height.1ex }} &%
   \global\@mm\@nn \global\divide\@mm\@base 
   \multiply\@mm\@base \advance\@nn-\@mm 
   \the\@nn \xdef\@digits{\the\@nn.\@digits}}%
\fi
%
\leavevmode\oalign{$#2_{10}:$\hfil\cr
      $\left.
      \begin{tabular}{r|l}
         \boucle \onerow \\ \ifnum\@nn>\@baseminusone\global\@nn\@mm \repeat
      \end{tabular}\right\rbrace=
      \mathtt{\@digits}_{#1}$}}     % \hfil removed from the macro

\makeatother

\begin{document}\thispagestyle{empty}

\lineskip12pt

  \baseexpansion{1000}\hfil
  \baseexpansion[3]{1000}\hfil
  \baseexpansion[4]{1000}\hfil
  \baseexpansion[5]{1000}\hfil
  \baseexpansion[6]{1000}\hfil
  \baseexpansion[7]{1000}\hfil
  \baseexpansion[8]{1000}\hfil
  \baseexpansion[9]{1000}\hfil
  \baseexpansion[10]{1000}\hfil
  \baseexpansion[11]{1000}\hfil
  \baseexpansion[12]{1000}\hfil
  \baseexpansion[13]{1000}\hfil
  \baseexpansion[14]{1000}\hfil
  \baseexpansion[15]{1000}\hfil
  \baseexpansion[16]{1000}\hfil
  \baseexpansion{1024}\hfil
  \baseexpansion[16]{1024}\hfil
  \baseexpansion[3]{6561}\hfil
  \baseexpansion[111]{1000000}\hfil
  \baseexpansion[111]{1000000000}\hfil
  \baseexpansion[7]{1000000000}\par

\end{document}

examples

digits

\documentclass{article}
\usepackage[left=1cm, right=2cm, vmargin=1cm]{geometry}

%%%-----------------------------------------------------------------------------
%%% macros to display the computation of a decimal representation of a positive
%%% integer given in base b representation with b at most 36

\makeatletter

\newcount\@nn
\newcount\@mm
\newcount\@base

% globally sets the counter \@mm to the decimal number represented by #1
% which is either a digit 0-9 or a letter A-Z or a-z
% no check on input done!
%\def\@set@mmto #1{\@mm`#1 \advance\@mm-48 
%      \ifnum\@mm>48 \advance\@mm-39 \else
%      \ifnum\@mm>16 \advance\@mm-7 \fi\fi \global\@mm\@mm}
% I had initially:
\def\@set@mmto #1{\@mm`#1 
  \ifnum\@mm>96 \advance\@mm-87 \else
  \ifnum\@mm>64 \advance\@mm-55 \else
  \advance\@mm-48 \fi\fi \global\@mm\@mm}

% prepares the first three entries of a row of the future tabular
% \@nn represents the decimal number so far computed, and will
% turn into base times itself plus new digit
% global assignments to transcend cells               
\def\@mostofonerow#1{\xdef\@digitssofar{\@digitssofar#1}%
    \@set@mmto #1%
    $\mathtt{\@digitssofar_{\the@base}}\rightarrow\the\@mm\;$%
    &%
    ${}+\the@base\times\the\@nn$%
    \multiply\@nn\@base
    \advance\@nn\@mm
    \global\@nn\@nn
    &${}={}$&}

% this is for displaying the final result in a box
\def\@endfinalrow{\fbox{$\the\@nn_{10}$}\\}

% this is the non-boxed intermediate result ending a row
\def\@endnormalrow{$\the\@nn$\\}

% recursive construction of successive rows
\def\@makenextrows#1{\ifx#1.\@endfinalrow\else
          \@endnormalrow\@mostofonerow#1\expandafter\@makenextrows\fi}

% first step for initialization. Checks for empty argument.
\def\@makerows #1{\ifx#1.\else\@mostofonerow#1\expandafter\@makenextrows\fi}

%% actually constructs the tabular with the computation
%% [moved to \todecimal]
%\def\@displayrows #1{{\setlength{\tabcolsep}{0pt}%
%               \begin{tabular}[t]{r|lcl}#1\end{tabular}}}

\newcommand{\todecimal}[2][2]{%
\@base=#1\def\the@base{#1}%
\@nn=0
\def\@digitssofar{}%
\oalign{$\mathtt{#2_{#1}}:$\hfil\cr
%%%% replaced
%%%% \expandafter\@displayrows\expandafter{\@makerows #2.}}} 
%%%% with the simpler: 
        {%
         \setlength{\tabcolsep}{0pt}%
         \begin{tabular}[t]{r|lcl}
         \@makerows #2.
         \end{tabular}%
        }%
       }%
} % end ot \todecimal

\makeatother

\begin{document}
\todecimal{0}\medskip

\todecimal{1}\medskip

\todecimal{10101110}\medskip

\todecimal[16]{AE}\medskip

\todecimal[16]{aE}\medskip

\todecimal[7]{351}\medskip

\todecimal[36]{zz}\medskip

\todecimal[36]{xYz}

\end{document}

todecimal

  • Be sure to pass a counter name to \@arabalpha or you'll have bad surprises; \ifcase\numexpr#1\relax 0 is safer (but requires e-TeX, of course). – egreg Feb 02 '13 at 16:58
  • @egreg thanks for pointing this out to people who might visit this page. I was aware of it and the \@arabalpha is only to be used here. –  Feb 02 '13 at 20:10
  • @egreg or \ifcase #1\zero\or1\or... with \chardef\zero\0 ` –  Feb 03 '13 at 11:41
  • Yes, if all you need is to print a 0; you're losing full expandability, of course. – egreg Feb 03 '13 at 12:12
  • @egreg @JosephWright Some person or software keeps on modifying my code. I read now \newcommand{\baseexpansion}[2][1] where my original file from which I copy-pasted had \newcommand{\baseexpansion}[2][2] and I never never wrote [2][1]. And similarly I already manually reverted \newcommand{\todecimal}[2][4] to my original \newcommand{\todecimal}[2][2]. I don't know what's going on here. Perhaps the [2][1] was there when I already reverted the [2][4]. –  Feb 03 '13 at 14:00
  • I have edited myself to re-establish the \newcommand{\baseexpansion}[2][2] which was the code I uploaded. I don't know why at some point it was converted to \newcommand{\baseexpansion}[2][1] which obviously did not originate with me. –  Feb 03 '13 at 15:50
  • @jfbu: I think I know what happening, it seems to be a really weird bug in the stackexchange engine. When new links and images are inserted, the markdown numbers of the links can change, and this has to be taken care of. Now your [2][2] is interpreted as a link to link number 2, with link description "2". And your old link number 2 got the new number 4 when you inserted some new images, so [2][2] was changed to [2][4]. In the edit history it looks as if you did all this yourself and are complaining about your other self :-) – Hendrik Vogt Feb 03 '13 at 22:58
  • @HendrikVogt this makes sense! which one of my other selves are you referring to? I keep complaining about most of them ;-) –  Feb 04 '13 at 07:18
  • @jfbu: I posted a bug report over at Meta.SO. – Hendrik Vogt Feb 04 '13 at 09:05
  • @HendrikVogt great; but I should register there to be allowed to upvote your post! –  Feb 04 '13 at 13:31
22

The unavoidable LaTeX3 solution.

The optional argument to \decbin states the number of bits (default 8); \bitcalc should be used in math mode.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% the needed variables
\tl_new:N \l__bee_bindigits_tl
\seq_new:N \l__bee_quotients_seq
\seq_new:N \l__bee_remainders_seq

% the user level macros
\NewDocumentCommand{\decbin}{ O{8} m }
 {
  \bee_decbin:nn { #1 } { #2 }
 }
\NewDocumentCommand{\bitcalc}{m}
 {
  \bee_bitcalc:n {#1}
 }

% the internal functions
\cs_new:Npn \bee_decbin:nn #1 #2
 {
  \int_compare:nTF { #2 >= 1 \prg_replicate:nn { #1 } { *2 } }
   {
    BAD! % too few bits
   }
   {
    \bee_print_decbin:nn { #1 } { #2 }
   }
 }
\cs_new_protected:Npn \bee_print_decbin:nn #1 #2
 {
  % compute the binary representation
  \tl_set:Nx \l__bee_bindigits_tl { \int_to_binary:n { #2 } }
  % pad with zeros
  \prg_replicate:nn { #1 - \tl_count:N \l__bee_bindigits_tl }
   { \tl_put_left:Nn \l__bee_bindigits_tl { 0 } }
  % print the original number
  $#2\sb{10}$
  % print the boxed binary digits
  \tl_map_inline:Nn \l__bee_bindigits_tl { \,\fbox{##1} }
 }

\cs_new_protected:Npn \bee_bitcalc:n #1
 {
  % print the number and start the recursion
  #1\sb{10}\to
  \seq_clear:N \l__bee_quotients_seq
  \seq_clear:N \l__bee_remainders_seq
  \bee_bitcalc_aux:n { #1 }
  % after the recursion print the binary representation
  \int_to_binary:n { #1 }\sb{2}
 }
\cs_new_protected:Npn \bee_bitcalc_aux:n #1
 {
  % if the quotient is nonzero store the current quotient
  % and the remainder of the division by 2, then repeat;
  % otherwise print the result
  \int_compare:nTF { #1 > 0 }
   {
    \seq_put_right:Nn \l__bee_quotients_seq { 2)\!\underline{\,\, #1 } }
    \seq_put_right:Nx \l__bee_remainders_seq { \int_mod:nn { #1 } { 2 } }
    \bee_bitcalc_aux:x { \int_div_truncate:nn { #1 } { 2 } }
   }
   {
    \bee_print_computation:
   }
 }
\cs_generate_variant:Nn \bee_bitcalc_aux:n { x }
\cs_new_protected:Npn \bee_print_computation:
 {
  \left\{\left.\kern-\nulldelimiterspace
   % print the array of quotients
   \begin{array}{r}\seq_use:Nnnn \l__bee_quotients_seq { \\ } { \\ } { \\ }\end{array}
   \right\uparrow
   % print the array of remainders
   \begin{array}{c}\seq_use:Nnnn \l__bee_remainders_seq { \\ } { \\ } { \\ }\end{array}
   \right\}
 }
\ExplSyntaxOff

\begin{document}
\decbin{1}

\decbin{255}

\decbin[16]{256}

\[
\bitcalc{156}
\]

\end{document}

enter image description here

With a straightforward change to a couple of macros we can extend \bitcalc to do the transformation to an (almost) arbitrary base:

\NewDocumentCommand{\bitcalc}{ O{2} m }
 {
  \bee_bitcalc:nn { #1 } { #2 }
 }
\cs_new_protected:Npn \bee_bitcalc:nn #1 #2
 {
  % print the number and start the recursion
  #2\sb{10}\to
  \seq_clear:N \l__bee_quotients_seq
  \seq_clear:N \l__bee_remainders_seq
  \bee_bitcalc_aux:nn { #1 } { #2 }
  % after the recursion print the binary representation
  \mathrm{ \int_to_base:nn { #2 } { #1 }\sb{ #1 } }
 }
\cs_new_protected:Npn \bee_bitcalc_aux:nn #1 #2
 {
  % if the quotient is nonzero store the current quotient
  % and the remainder of the division by #1, then repeat;
  % otherwise print the result. Here #1 is the base.
  \int_compare:nTF { #2 > 0 }
   {
    \seq_put_right:Nn \l__bee_quotients_seq { #1)\!\underline{\,\, #2 } }
    \seq_put_right:Nx \l__bee_remainders_seq { \int_mod:nn { #2 } { #1 } }
    \bee_bitcalc_aux:nx { #1 } { \int_div_truncate:nn { #2 } { #1 } }
   }
   {
    \bee_print_computation:
   }
 }
\cs_generate_variant:Nn \bee_bitcalc_aux:nn { nx }

No change is needed to \bee_print_computation:. The input

\[
\bitcalc[4]{156}\quad\bitcalc[16]{156}
\]

will generate

enter image description here

The function \int_to_base:nn supports bases from 2 to 36.

Some fixes after a few years

The function \int_to_binary:n has been deprecated. I added a *-version of \bitcalc that adds & just before the arrow, for use in alignments.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
% the needed variables
\tl_new:N \l__bee_bindigits_tl
\seq_new:N \l__bee_quotients_seq
\seq_new:N \l__bee_remainders_seq

% the user level macros
\NewDocumentCommand{\decbin}{ O{8} m }
 {
  \bee_decbin:nn { #1 } { #2 }
 }
\NewDocumentCommand{\bitcalc}{ s O{2} m }
 {
  \bee_bitcalc:nnn { #2 } { #3 } { \IfBooleanT{#1}{&} }
 }

% the internal functions
\cs_new:Npn \bee_decbin:nn #1 #2
 {
  \int_compare:nTF { #2 >= 1 \prg_replicate:nn { #1 } { *2 } }
   {
    BAD! % too few bits
   }
   {
    \bee_print_decbin:nn { #1 } { #2 }
   }
 }
\cs_new_protected:Npn \bee_print_decbin:nn #1 #2
 {
  % compute the binary representation
  \tl_set:Nx \l__bee_bindigits_tl { \int_to_bin:n { #2 } }
  % pad with zeros
  \prg_replicate:nn { #1 - \tl_count:N \l__bee_bindigits_tl }
   { \tl_put_left:Nn \l__bee_bindigits_tl { 0 } }
  % print the original number
  $#2\sb{10}$
  % print the boxed binary digits
  \tl_map_inline:Nn \l__bee_bindigits_tl { \,\fbox{##1} }
 }

\cs_new_protected:Npn \bee_bitcalc:nnn #1 #2 #3
 {
  % print the number and start the recursion
  #2\sb{10}#3\to
  \seq_clear:N \l__bee_quotients_seq
  \seq_clear:N \l__bee_remainders_seq
  \bee_bitcalc_aux:nn { #1 } { #2 }
  % after the recursion print the binary representation
  \mathrm{ \str_upper_case:f { \int_to_base:nn { #2 } { #1 } }\sb{ #1 } }
 }
\cs_new_protected:Npn \bee_bitcalc_aux:nn #1 #2
 {
  % if the quotient is nonzero store the current quotient
  % and the remainder of the division by #1, then repeat;
  % otherwise print the result. Here #1 is the base.
  \int_compare:nTF { #2 > 0 }
   {
    \seq_put_right:Nn \l__bee_quotients_seq { #1)\!\underline{\,\, #2 } }
    \seq_put_right:Nx \l__bee_remainders_seq { \int_mod:nn { #2 } { #1 } }
    \bee_bitcalc_aux:nx { #1 } { \int_div_truncate:nn { #2 } { #1 } }
   }
   {
    \bee_print_computation:
   }
 }
\cs_generate_variant:Nn \bee_bitcalc_aux:nn { nx }
\cs_new_protected:Npn \bee_print_computation:
 {
  \left\{
   % print the array of quotients
   \begin{array}{r}\seq_use:Nn \l__bee_quotients_seq { \\ } \end{array}
   \middle\uparrow
   % print the array of remainders
   \begin{array}{c}\seq_use:Nn \l__bee_remainders_seq { \\ } \end{array}
   \right\}
 }
\ExplSyntaxOff

\begin{document}
\decbin{1}

\decbin{255}

\decbin[16]{256}

\[
\bitcalc{4096}
\]

\begin{align*}
\bitcalc*{156}      & \bitcalc*[3]{156} \\
\bitcalc*[8]{5656} & \bitcalc*[16]{5656}
\end{align*}

\end{document}

enter image description here

egreg
  • 1,121,712