15

I am teaching how to convert from one base to another base, however, I can't find a way to do something like this:

enter image description here

I know little about Tikz, the only thing I have been able to produce is a simple square with a couple of lines over it, so I don't even know where to start. Any suggestions? I don't mind typing all the numbers, what I want to do is to automatize the process of creating the lines.

4
  • 1
    I think How can I illustrate decimal to binary conversion? is what you are looking for. Apr 9, 2013 at 1:17
  • I have seen that post, but the style is different from the one I want. Unfortunately, I don't think the people I'm trying to teach this topic will understand the other way since I can hardly understand it.
    – hinafu
    Apr 9, 2013 at 1:24
  • 1
    @hinafu I have never understood any diagram arithmetics :-/ IMHO all these tries to make things simple are stupid and make it only more complicated...
    – yo'
    Apr 9, 2013 at 13:55
  • @tohecz I would agree with you if I wouldn't have to teach this to 10 years old kids, because I'm pretty sure they'll learn this easily this way than doing it other way.
    – hinafu
    Apr 9, 2013 at 14:04

3 Answers 3

21

EDIT: This answer contains 3 versions, the first one based on my misunderstanding of the approach given above, and the second one is (I hope) a more correct interpretation. The third version allows conversions for bases up to base 36(!) (but restricted to the range of numbers for the pgfmath engine, i.e., 0-16383).

The first one:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\newcount\total
\newcount\lasttotal
\newcount\targetbase

\def\basetenconversiontable#1#2{%
    \begin{tikzpicture}[every node/.style={minimum width=1cm, minimum height=0.5cm}, x=1cm,y=0.5cm]
    %
    \total=#1%
    \targetbase=#2
    \def\newnumber{}
    %
    \pgfmathloop
    \ifnum\total<1
    \else
        %
        \ifnum\pgfmathcounter>1
            \node at (\pgfmathcounter, -\pgfmathcounter+1) (tmp) {\the\targetbase};
            \draw (tmp.north west) |- (tmp.south east);
            %
            \node at (\pgfmathcounter-1, -\pgfmathcounter) (tmp) {\pgfmathparse{int(\total*\targetbase)}\pgfmathresult};
            \draw (tmp.south west) -- (tmp.south east);
            %
            \pgfmathparse{int(\lasttotal-\total*\targetbase)}%
            \let\digit=\pgfmathresult
            \node at (\pgfmathcounter-1, -\pgfmathcounter-1) [text=red] {\digit};
            \edef\newnumber{\digit\newnumber}
        \fi
        %
        \ifnum\total<\targetbase
                \edef\newnumber{\the\total\newnumber}
            \node at (\pgfmathcounter, -\pgfmathcounter) [text=red]  {\the\total};
        \else
            \node at (\pgfmathcounter, -\pgfmathcounter) {\the\total};
        \fi
        \lasttotal=\total
        \divide\total by\targetbase
    \repeatpgfmathloop    
    \draw [->] (\pgfmathcounter-1,-\pgfmathcounter-1) -- ++(-0.5,0); 
    \node [anchor=west] at (1, -\pgfmathcounter-2) {$#1=\newnumber_{\the\targetbase}$};
    \end{tikzpicture}   
}

\begin{tabular}{c}
\basetenconversiontable{478}{7} \\ 
\basetenconversiontable{1362}{5} \\
\basetenconversiontable{365}{3} \\
\basetenconversiontable{637}{2}
\end{tabular}

\end{document}

enter image description here

The second one:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\newcount\columntotal
\newcount\nextcolumntotal
\newcount\tmptotal
\newcount\tmptmptotal

\newcount\targetbase
\newcount\digitcount


\def\getonedigit#1#2;{#1}
\def\getndigits#1{%
    \begingroup%
        \tmptotal=#1
        \pgfmathloop%
        \ifnum\tmptotal<10%
        \else%
            \divide\tmptotal by10%
        \repeatpgfmathloop%
        \pgfmathsmuggle\pgfmathcounter%
    \endgroup%
    \edef\ndigits{\pgfmathcounter}%
}

\def\baseconversiontable#1#2{%
    \begingroup%
    \getndigits{#1}%
    \pgfmathsetlengthmacro\tablecolumnwidth{\ndigits*width("$4$")}%
    \def\convertednumber{}%
    \begin{tikzpicture}
    \node (base conversion table) {%
        \begin{tikzpicture}
        [
            table node/.style={
                text width=\tablecolumnwidth, 
                inner sep=0pt,
                align=right, 
                minimum height=0.5cm, 
                minimum width=\tablecolumnwidth+5pt
            }, 
            x=\tablecolumnwidth+5pt,
            y=0.5cm
        ]
            \targetbase=#2
            \dobaseconversiontable{#1}%
        \end{tikzpicture}%
    };%
    \draw [->](base conversion table.south east) -- ++(-0.5,0);
    \node [below, anchor=north west] at (base conversion table.south west) {$#1=\convertednumber_{#2}$};    
    \end{tikzpicture}
    \endgroup%
}


\def\dobaseconversiontable#1{%
    \columntotal=#1%
    \getndigits{\columntotal}%
    \tmptotal=#1%
    \divide\tmptotal by\targetbase
    \nextcolumntotal=\tmptotal
    %
    \ifnum\columntotal<\targetbase
        \node at (0, 0) [table node, red] (@) {$\the\columntotal$};%
        \xdef\convertednumber{\the\columntotal\convertednumber}%
    \else%
        \node at (1, 0) [table node] (@) {$\the\targetbase$};%
        \draw (@.north west) |- (@.south east);
        %
        \getndigits{\tmptotal}%
        \digitcount=\ndigits%
        %   
        \node at (0,0) [table node] {$\the\columntotal$};%
        \tmptmptotal=\tmptotal
        \pgfmathloop
        \ifnum\digitcount=0
        \else%
            \tmptmptotal=\tmptotal
            \ifnum\digitcount>0
                \tmptmptotal=\expandafter\getonedigit\the\tmptmptotal;
            \fi
            \pgfmathparse{int(\tmptmptotal*\targetbase*10^(\digitcount-1))}%
            \let\remainder=\pgfmathresult
            \pgfmathsetcount\columntotal{\columntotal-\remainder}%
            \advance\digitcount by-1
            \pgfmathsetcount\tmptotal{\tmptotal-\tmptmptotal*(10^\digitcount)}%
            \ifnum\columntotal<\targetbase
                \node at (0,-\pgfmathcounter*2) [table node, red] (@) {$\the\columntotal$};%
                \xdef\convertednumber{\the\columntotal\convertednumber}%
                \digitcount=0%
            \else
                \node at (0,-\pgfmathcounter*2) [table node](@) {$\the\columntotal$};%
            \fi
            \draw (@.north west) -- (@.north east);
            \node at (0,-\pgfmathcounter*2+1) [table node] {$\remainder$};%
        \repeatpgfmathloop%
        \tikzset{shift={(1,-1)}}%
        \expandafter\dobaseconversiontable\expandafter{\the\nextcolumntotal}%
    \fi
}%

\begin{tabular}{c}
\baseconversiontable{478}{7}\\
\baseconversiontable{1366}{5}\\
\baseconversiontable{365}{3}\\
\baseconversiontable{711}{2}    
\end{tabular}

\end{document}

enter image description here

Third version. I think it works correctly. It's all a teensy bit kludgy anyway.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\newcount\columntotal
\newcount\nextcolumntotal
\newcount\tmptotal
\newcount\tmptmptotal

\newcount\targetbase
\newcount\digitcount

\def\digittoalpha#1{%
    \ifcase#1\relax0\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 p\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else?\fi%
}

\def\getonedigit#1#2;{#1}
\def\getndigits#1{%
    \begingroup%
        \tmptotal=#1
        \pgfmathloop%
        \ifnum\tmptotal<10%
        \else%
            \divide\tmptotal by10%
        \repeatpgfmathloop%
        \pgfmathsmuggle\pgfmathcounter%
    \endgroup%
    \edef\ndigits{\pgfmathcounter}%
}

\def\baseconversiontable#1#2{%
    \begingroup%
    \getndigits{#1}%
    \pgfmathsetlengthmacro\tablecolumnwidth{\ndigits*width("$4$")}%
    \gdef\convertednumber{}%
    \begin{tikzpicture}
    \node (base conversion table) {%
        \begin{tikzpicture}
        [
            table node/.style={
                anchor=north,
                text width=\tablecolumnwidth, 
                inner sep=0pt,
                align=right, 
                minimum height=0.5cm, 
                minimum width=\tablecolumnwidth+5pt
            }, 
            x=\tablecolumnwidth+5pt,
            y=0.5cm
        ]
            \targetbase=#2
            \dobaseconversiontable{#1}%
        \end{tikzpicture}%
    };%
    \draw [->](base conversion table.south east) -- ++(-0.5,0);
    \node [below, anchor=north west] at (base conversion table.south west) {$#1=\convertednumber_{#2}$};    
    \end{tikzpicture}
    \endgroup%
}


\def\dobaseconversiontable#1{%
    \columntotal=#1%
    \getndigits{\columntotal}%
    \tmptotal=#1%
    \divide\tmptotal by\targetbase
    \nextcolumntotal=\tmptotal
    %
    \ifnum\columntotal<\targetbase
        \edef\currentdigit{\uppercase{\digittoalpha{\the\columntotal}}}%
        \ifnum\columntotal>9
            \edef\currentdigit{\noexpand\rm{\currentdigit}}%
        \fi
        \node at (0, 0) [table node] (@) {%
            \\% For some reason necessary.
            \ifnum\the\columntotal<10
                \color{red}$\the\columntotal$%
            \else
                $\the\columntotal$\\%
                \tikz\draw[->](0,0)(-0.75ex,0)--++(0,-0.5);\\%
                \color{red}\currentdigit%
            \fi
            };% 
        \expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\convertednumber%
        \expandafter\expandafter\expandafter{\expandafter\currentdigit\convertednumber}%
    \else%
        \node at (1, 0) [table node] (@) {$\the\targetbase$};%
        \draw (@.north west) |- (@.south east);
        %
        \getndigits{\tmptotal}%
        \digitcount=\ndigits%
        %   
        \node at (0,0) [table node] {$\the\columntotal$};%
        \tmptmptotal=\tmptotal
        \pgfmathloop
        \ifnum\digitcount=0
        \else%
            \tmptmptotal=\tmptotal
            \ifnum\digitcount>0
                \tmptmptotal=\expandafter\getonedigit\the\tmptmptotal;
            \fi
            \pgfmathparse{int(\tmptmptotal*\targetbase*10^(\digitcount-1))}%
            % Hmm this is a kludge.
            \ifnum\pgfmathresult>\columntotal%
                \pgfmathparse{int(\pgfmathresult/10)}%
            \fi%
            \let\remainder=\pgfmathresult%
            \pgfmathsetcount\columntotal{\columntotal-\remainder}%
            \advance\digitcount by-1
            \pgfmathsetcount\tmptotal{\tmptotal-\tmptmptotal*(10^\digitcount)}%
            \ifnum\columntotal<\targetbase
                \edef\currentdigit{\uppercase{\digittoalpha{\the\columntotal}}}%
                \ifnum\columntotal>9
                    \edef\currentdigit{\noexpand\rm{\currentdigit}}%
                \fi
                \node at (0,-\pgfmathcounter*2) [table node] (@) {%
                    \\
                    \ifnum\columntotal<10
                        \color{red}$\the\columntotal$%
                    \else
                        $\the\columntotal$\\%
                        \tikz\draw[->](0,0)(-0.75ex,0)--++(0,-0.5);\\%
                        \color{red}\currentdigit%
                    \fi
                    };%                     
                \expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\convertednumber%
                    \expandafter\expandafter\expandafter{\expandafter\currentdigit\convertednumber}%
                \digitcount=0%
            \else
                \node at (0,-\pgfmathcounter*2) [table node](@) {$\the\columntotal$};%
            \fi
            \draw (@.north west) -- (@.north east);
            \node at (0,-\pgfmathcounter*2+1) [table node] {$\remainder$};%
        \repeatpgfmathloop%
        \tikzset{shift={(1,-1)}}%
        \expandafter\dobaseconversiontable\expandafter{\the\nextcolumntotal}%
    \fi
}%

\begin{tabular}{ccc}
\baseconversiontable{3022}{16}&&
\baseconversiontable{1462}{12}\\
\baseconversiontable{5407}{19}&&
\baseconversiontable{3887}{36}  
\end{tabular}

\end{document}

enter image description here

5
  • Without the table and for further reference; PGF math also provides macros for base to base conversations; here \pgfmathdectoBase{\newnumber}{\total}{\targetbase} may be used. Apr 9, 2013 at 10:35
  • @Qrrbrbirlbel: In fact, I used almost exactly the same technique that was used by the author of \pgfmathdectoBase. Apr 9, 2013 at 11:29
  • This is great! Actually, this is the way I learned this method, without writing down all the other operations, but I wanted them because the kids I'm teaching this are younger than I was when I first learned this, but anyway, this is fantastic!
    – hinafu
    Apr 9, 2013 at 13:27
  • It would be perfect with the support of higher bases like \baseconversiontable{711}{16} for example. It just needs a proper digits in the result.
    – g.kov
    Apr 10, 2013 at 7:38
  • @g.kov I've updated the answer. It seems to work ok. Apr 10, 2013 at 8:54
22

One can do a good job without TikZ using a standard array environment:

\documentclass[10pt,letterpaper]{amsart}
\usepackage{xcolor}

\newcommand\myrule[1]{\multicolumn{1}{c|}{#1}}
\newcommand\myred[1]{\textcolor{red}{#1}}

\begin{document}

\begin{gather*}
\begin{array}{*{7}c}
4 & 7 & \myrule{8} & 7 \\
\cline{4-5}
4 & 2 & & 6 & \myrule{8} & 7 \\
\cline{6-6}
& 5 & 8 & 6 & 3 & \myrule{9} & 7 \\
\cline{4-5}\cline{7-7}
& 5 & 6 & & \myred{5} & 7 & \myred{1} \\
\cline{2-3}\cline{6-6}
& & \myred{2} & & & \myred{2}
\end{array} \\
\longleftarrow \\
478 = 1252_{7}
\end{gather*}

\end{document}

enter image description here

After Qrrbrbirlbel's suggestion to change the spacing between digits belonging to a number, one could get:

\documentclass[10pt,letterpaper]{amsart}
\usepackage{xcolor}

\newcommand\myrule[1]{\multicolumn{1}{@{}c|}{#1}}
\newcommand\myred[1]{\textcolor{red}{#1}}

\begin{document}

\begin{gather*}
\begin{array}{c@{\,}c@{\,}cc@{\,}ccc}
4 & 7 & \myrule{8} & 7 \\
\cline{4-5}
4 & 2 & & 6 & \myrule{8} & 7 \\
\cline{6-6}
& 5 & 8 & 6 & 3 & \multicolumn{1}{c|}{9} & 7 \\
\cline{4-5}\cline{7-7}
& 5 & 6 & & \myred{5} & 7 & \myred{1} \\
\cline{2-3}\cline{6-6}
& & \myred{2} & & & \myred{2}
\end{array} \\
\longleftarrow \\
478 = 1252_{7}
\end{gather*}

\end{document}

enter image description here

And a TikZ solution:

\documentclass[10pt,letterpaper]{amsart}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}

\begin{tikzpicture}
\matrix[matrix of nodes,column sep=-5.5pt,nodes in empty cells] (mat)
{
4 & 7 & 8 & [7pt]7 & & [7pt] \\
4 & 2 & & 6 & 8 & 7 & [7pt]{} \\
& 5 & 8 & 6 & 3 & 9 & 7 \\
& 5 & 6 & & |[red]|5 & 7 & |[red]|1 \\
& & |[red]|2 & & & |[red]|2 \\
};
\draw ([xshift=-1.5pt,yshift=-2pt]mat-1-4.north west) |- ([xshift=-3.5pt]mat-1-6.south west) |- ([xshift=-3.5pt]mat-2-7.south west) |- (mat-3-7.south east);
\draw (mat-4-2.south west) -- (mat-4-3.south east);
\draw (mat-3-4.south west) -- (mat-3-5.south east);
\draw (mat-4-6.south west) -- (mat-4-6.south east);

\node at ([yshift=-10pt]current bounding box.south)
  {$\longleftarrow$};
\node at ([yshift=-10pt]current bounding box.south)
  {$478=1252_{7}$};
\end{tikzpicture}

\end{document}

enter image description here

In a comment a special alignment for the first seven was requested:

\documentclass[10pt,letterpaper]{amsart}
\usepackage{xcolor}

\newcommand\myrule[1]{\multicolumn{1}{@{}c|}{#1}}
\newcommand\myred[1]{\textcolor{red}{#1}}

\begin{document}

\begin{gather*}
\begin{array}{c@{\,}c@{\,}cc@{\,}ccc}
4 & 7 & \myrule{8} & \multicolumn{2}{c}{7} \\
\cline{4-5}
4 & 2 & & 6 & \myrule{8} & 7 \\
\cline{6-6}
& 5 & 8 & 6 & 3 & \multicolumn{1}{c|}{9} & 7 \\
\cline{4-5}\cline{7-7}
& 5 & 6 & & \myred{5} & 7 & \myred{1} \\
\cline{2-3}\cline{6-6}
& & \myred{2} & & & \myred{2}
\end{array} \\
\longleftarrow \\
478 = 1252_{7}
\end{gather*}

\end{document}

enter image description here

7
  • 3
    A suggestion: Reduce the space between digits belonging to a number (either with one number per cell and with \hphantoms to align 42 under 478 or by changing the space between columns). Apr 9, 2013 at 1:54
  • 1
    @Qrrbrbirlbel yes, that is a nice suggestion. Better now? Apr 9, 2013 at 2:05
  • Ok, this will do it. Thanks a lot! I'm still waiting for a TikZ solution though, where the 7s could be perfectly aligned with the lines below them, but that's just a tiny detail. Thanks again!
    – hinafu
    Apr 9, 2013 at 2:09
  • 1
    @hinafu I've updated my answer with a TikZ possibility. Apr 9, 2013 at 2:32
  • 1
    @hinafu please see my updated answer. Apr 9, 2013 at 3:05
6

Another TiKZ solution. The code was provided some time ago by JLDiaz in CervanTeX, (spanish TeX group) mail list.

Every successive division draws a matrix of nodes relative to previous one. It also labels every reminder to help to draw lines between them or place some other information.

It doesn't show the complete division, only dividend, divisor and remainder. Quotient is next division dividend.

\documentclass[tikz]{standalone}

\usetikzlibrary{matrix,positioning}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Macros for ``successive divisions'' 
%
\def\Division#1#2#3{ % Dividend, divisor, remainder
 \matrix (D) [matrix of nodes,
              below=0pt of D-1-2.south east,
              row sep=1pt, column sep=1pt,
              every node/.append style={minimum width=12mm}] {
   #1 \pgfmatrixnextcell #2 \\
   |[marcar] (R#1)| #3      \\
 };
 \draw[shorten >=2pt, shorten <=2pt]
   (D-1-2.north west) |- (D-1-2.south east);
}
\def\FinDivision#1{
\node[marcar, below=2pt of D-1-2.south] (C)(C)  {#1};
}
\tikzset{marcar/.style={circle,draw,inner sep=2pt,minimum width=0pt,
fill=yellow!10}}

\begin{document}
\begin{tikzpicture}
  \coordinate (D-1-2) at (0,0) {}; % We must start with this command.
  \Division{25}{2}{1} % First dividend, divisor, remainder
  \Division{12}{2}{0} % Dividend (previous quotient), divisor, remainder
  \Division{6}{2}{0}  
  \Division{3}{2}{1}  
  \FinDivision{1}     % Last remainder.

% We can draw an arrow jumping from one remainder 
% to the next one. Every reminder is a node called
% Rdividend. Last remainder is node C.
  \draw[shorten <=1mm, ->, dashed] (C) to[out=-150,in=-65] (R3);
  \draw[shorten <=1mm, ->, dashed] (R3) to[out=-150,in=-65] (R6);
  \draw[shorten <=1mm, ->, dashed] (R6) to[out=-150,in=-65] (R12);
  \draw[shorten <=1mm, ->, dashed] (R12) to[out=-150,in=-65] (R25);

% Some more information:
  \node (MSB) at ([yshift=-1.3cm]R6.south) {Most significant bit (MSB)};    
  \node (LSB) at ([yshift=-2mm]MSB.south) {Less significant bit (LSB)}; 
\draw[ ->] (MSB.east) to[out=30,in=-55] (C);
\draw[ ->] (LSB.west) to[out=150,in=-95] (R25);
\end{tikzpicture}
\end{document}

enter image description here

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.