Creating figures to show binary values

I'm working on a paper that deals heavily with floating point values, and I need to make figures to represent 32 bit binary values. The code below is what I came up with, and visually it is basically what I want. However at the least I'd like to wrap it in a function since it will need to be used fairly often, but I haven't been able to make that work. I tried putting the picture portion in the function, but kept getting errors about how \begin{figure} was being terminated by a \end{document}. Also, if you zoom in on the figure you can see that the boxes don't always line up correctly, and I'm not quite sure how to fix that.

\begin{figure}
\setlength{\unitlength}{1mm}
\setlength{\fboxsep}{0mm}
\centering
\begin{picture}(130,16)
% sign bit
\put(2,4){\framebox(4,8){0}}
% exponent
\put(6,4){\framebox(4,8){1}}
\put(10,4){\framebox(4,8){0}}
\put(14,4){\framebox(4,8){0}}
\put(18,4){\framebox(4,8){0}}
\put(22,4){\framebox(4,8){0}}
\put(26,4){\framebox(4,8){0}}
\put(30,4){\framebox(4,8){0}}
\put(34,4){\framebox(4,8){0}}
% fraction
\put(38,4){\framebox(4,8){1}}
\put(42,4){\framebox(4,8){0}}
\put(46,4){\framebox(4,8){0}}
\put(50,4){\framebox(4,8){1}}
\put(54,4){\framebox(4,8){0}}
\put(58,4){\framebox(4,8){0}}
\put(62,4){\framebox(4,8){1}}
\put(66,4){\framebox(4,8){0}}
\put(70,4){\framebox(4,8){0}}
\put(74,4){\framebox(4,8){0}}
\put(78,4){\framebox(4,8){0}}
\put(82,4){\framebox(4,8){1}}
\put(86,4){\framebox(4,8){1}}
\put(90,4){\framebox(4,8){1}}
\put(94,4){\framebox(4,8){1}}
\put(98,4){\framebox(4,8){1}}
\put(102,4){\framebox(4,8){1}}
\put(106,4){\framebox(4,8){0}}
\put(110,4){\framebox(4,8){1}}
\put(114,4){\framebox(4,8){0}}
\put(118,4){\framebox(4,8){0}}
\put(122,4){\framebox(4,8){0}}
\put(126,4){\framebox(4,8){0}}
% upper labels
\put(0,14){\scriptsize{MSB}}
\put(126,14){\scriptsize{LSB}}
%lower labels
\put(3,0){\scriptsize{S}}
\put(7,0){\line(0,1){2}}
\put(7,1){\vector(1,0){8}}
\put(16,0){\scriptsize{Exponent}}
\put(37,1){\vector(-1,0){8}}
\put(37,0){\line(0,1){2}}
\put(39,0){\line(0,1){2}}
\put(39,1){\vector(1,0){38}}
\put(79,0){\scriptsize{Fraction}}
\put(130,1){\vector(-1,0){38}}
\put(130,0){\line(0,1){2}}
\end{picture}
\caption{The value 3.14159 stored as a \code{float}.}
\label{figure:pi_example}
\end{figure}

-

One can indeed define a command and automatize a bit.

\documentclass{article}

\usepackage{xinttools}

\newcounter{bitindex}

\newcommand\bitpicture [3]{%
\setlength{\unitlength}{1mm}
\setlength{\fboxsep}{0mm}
\begin{picture}(130,16)
% sign bit
\put(2,4){\framebox(4,8){#1}}
% exponent
\setcounter{bitindex}{1}%
\xintFor* ##1 in {#2}
\do
{\put(\numexpr 2+4*\value{bitindex},4){\framebox(4,8){##1}}%
\stepcounter{bitindex}}%
% fraction
\setcounter{bitindex}{1}%
\xintFor* ##1 in {#3}
\do
{\put(\numexpr 34+4*\value{bitindex},4){\framebox(4,8){##1}}%
\stepcounter{bitindex}}%
% upper labels
\put(0,14){\scriptsize{MSB}}
\put(126,14){\scriptsize{LSB}}
%lower labels
\put(3,0){\scriptsize{S}}
\put(7,0){\line(0,1){2}}
\put(7,1){\vector(1,0){8}}
\put(16,0){\scriptsize{Exponent}}
\put(37,1){\vector(-1,0){8}}
\put(37,0){\line(0,1){2}}
\put(39,0){\line(0,1){2}}
\put(39,1){\vector(1,0){38}}
\put(79,0){\scriptsize{Fraction}}
\put(130,1){\vector(-1,0){38}}
\put(130,0){\line(0,1){2}}
\end{picture}%
}

\begin{document}
\begin{figure}
\centering
\bitpicture {0}{10000000}{10010010000111111010000}
\caption{The value 3.14159 stored as a \texttt{float}.}
\label{figure:pi_example}
\end{figure}
\end{document}


Furthermore, it could be possible to actually compute the binary representation starting from the decimal one (if someone explains to me the rule I can implement it).

As a complement here is some code to convert into Double Binary (see wikipedia). On input anything acceptable by the macros of xintfrac, on output the Double Binary format on 64 bits, in three macros \BDsign, \BDexponent, \BDfraction. As the input may have hundreds of digits, it is first converted into a Decimal Float with 24 digits precision. The conversion to Double Binary is then done from that starting point with 24 decimal digits and a power of ten exponent (notice that xint allows all the way up to 10^2147483647, thus the code treats NaN and it also deals with sub-normal numbers). There is also a macro going the reverse way.

Naturally this only illustrates the conversion as implemented here, conversion whose steps are explained in the code comments.

The \bitpicture from the code above could be redone for the 64 bits case, only a few things need to be changed and \bitpicture\BDsign\BDexponent\BDfraction would work. But here I chose a simpler inline representation.

\documentclass{article}
\usepackage{xintfrac}
\usepackage{xintbinhex}
\usepackage{xintexpr}
\usepackage{color}
\usepackage[paperheight=50cm,vscale=0.9,hscale=0.72]{geometry}

\makeatletter
\newcommand{\ToDouble}[1]{%
% This commands handles arbitrary expandable material producing
% an input number in the formats as understood by xint: integers,
% fractions, decimal numbers, scientific notation, or fractions with such
% numbers etc... for example 12.34, or 1.07/3.25 or 12e7, or
% 1.25e7/3.12e5
% It computes the Double Precision Binary representation and puts the
% 64 binary digits in the three macros \BDsign (1bit), \BDexponent
% (11bit), \BDfraction (52bit)
\edef\TBD@x {#1}%
% Then we convert #1 to float with 24 digits of precision, this step
% is in case
% we have some very long input like pi with 1000 digits for example.
% We don't want to have to do computations with that many digits
% aftewards.
% (\oodef = \def with twice expansion of the contents)
% 24 digits is overkill.
\oodef\TBD@x {\xintFloat [24]{\TBD@x}}%
\xintifSgn \TBD@x
{\def\BDsign {1}\oodef\TBD@x {\xintAbs {\TBD@x}}\TBD@Parse }
{\def\BDsign {0}\def\BDexponent{00000000000}%
\def\BDfraction{0000000000000000000000000000000000000000000000000000}}
{\def\BDsign {0}\TBD@Parse }%
}%

\def\TBD@get@t #1[#2]{\def\TBD@t {#2}}%

\def\TBD@Parse {%
% first we get the power of 10 such that 10^t <= x < 10^{t+1}
% this is done by converting to float with 1 digit of precision.
% \XINTinFloat will produce d[t], with 1<= d <= 10 (10 is obtained
% only from upper rounding,  for example 9.95 becomes 10[0])
% Note that t may be as big as 2147483647 which is way beyond
% what can be represented as a double
\oodef\TBD@tmp {\XINTinFloat [1]\TBD@x}%
\expandafter\TBD@get@t\TBD@tmp
% What we really want is exponent of a power of two which is about
% 3.32 times t:
% 1/log10(2) = 3.3219280948873623478703194294...
% we don't need that much precision as allowable range of decimal exponents
% (single precision) from -38 to +38 for normal and -45 to -38 for
% subnormal numbers
% (double precision) from -324 to +308
% we thus take a lower bound, and then multiply by 2 or divide by 2 the
% number of times (3 or perhaps 4 times at most) to end up in the correct
% range 1<= f <2. We will then need to check for subnormal numbers.
% to reduce overhead in handling of y, we first check the size of t:
\xintifGt {\TBD@t}{1000}
{% too big number (10^1000)
\def\BDexponent {11111111111}%
\def\BDfraction
{1000000000000000000000000000000000000000000000000000}%
\TBD@abort }{}%
\xintifLt {\TBD@t}{-1000}
{% too close to zero number (10^-1000)
\def\BDexponent {00000000000}%
\def\BDfraction
{0000000000000000000000000000000000000000000000000000}%
\TBD@abort }{}%
% we are now guaranteed that \TBD@y will be usable with \numexpr,
% let's get it:
\oodef\TBD@y {\xintFloor {\xintMul {3.321928}{\TBD@t}}}%
% below apart from the float computation of the power of 2,
% the other operations are handled exactly
%   (\xintDiv does not do much as xint handles fractions natively,
%    it just prepares a fraction)
%   (the real work will be done by the comparison tests)
\oodef\TBD@z {\xintDiv {\TBD@x}{\xintFloatPow [24]{2}{\TBD@y}}}%
%
\xintloop
\xintifLt {\TBD@z}{1}
{\oodef\TBD@z {\xintMul {2}{\TBD@z}}%
\odef\TBD@y  {\the\numexpr \TBD@y-1}%
\iftrue }%
{\iffalse }% stop the loop if z >= 1
\repeat
%
\xintloop
\xintifLt {\TBD@z}{2}
{\iffalse }% stop the loop if z < 2
{\oodef\TBD@z {\xintDiv {\TBD@z}{2}}%
\odef\TBD@y  {\the\numexpr \TBD@y+1}%
\iftrue }%
\repeat
%
\odef \TBD@e {\the\numexpr 1023+\TBD@y }% biased exponent
% We need to check if we have a sub-normal number or NaN
\ifnum \TBD@e > 2046 % beyond allowable range of double precision
\def\BDexponent {11111111111}%
\def\BDfraction {1000000000000000000000000000000000000000000000000000}%
\else
\ifnum \TBD@e < 1
% sub-normal number
% x is theoretically less than 2^{-1022}
% however with the computations giving the z such that 1<= z < 2
% z is only an approximation to x 2^(-y)
% Thus it could be that the x is in fact 2^{-1022} or slightly
% greater and should then be represented as a normal number
% we forget about the computed z and work again starting from x
% We multiply x by 2^{1022+52}=2^{1074}
% 2^1074=2.024022533073106183524953467.. 10^323
% keep it with 24 digits precision -> 202402253307310618352495[300]
% then we round to the nearest integer and
% later we test to check if we have something too big
\oodef\TBD@w
{\xintiRound0 {\xintMul {\TBD@x}{202402253307310618352495[300]}}}%
%
\xintifGt{\TBD@w}{4503599627370495}
% 2^52= 4503599627370496
{% we have in fact a normal number between 2^{-1022} and 2^{-1021}
\def\BDexponent {00000000001}%
\oodef\TBD@f {\xintDecToBin {\TBD@w}}%
% we gobble the first 1 of the 53bit representation to get 52 bits.
\oodef\BDfraction {\expandafter\@gobble\TBD@f }%
}%
{% we really have a sub-normal number
\def\BDexponent {00000000000}%
% we add 2^52, convert to binary, gobble the first 1.
\oodef\BDfraction {\expandafter\@gobble\TBD@f }%
}%
\else
% 1<= e <= 2046: normal case
% 1<= z < 2 holds for the fraction part.
% We multiply by 2^52= 4503599627370496,
% round, convert to binary, and gobble the first 1.
% However rounding may have been up to 2^53, thus we test for
% that case and then use rather 2^53-1.
%
\oodef \TBD@f {\xintiRound0 {\xintMul {4503599627370496}{\TBD@z}}}%
%
\xintifEq {\TBD@f}{9007199254740992}
{\def\BDfraction
{1111111111111111111111111111111111111111111111111111}}%
{% convert to binary and gobble the first 1 of the 53bit
% representation
\oodef\TBD@f {\xintDecToBin {\TBD@f}}%
\oodef\BDfraction {\expandafter\@gobble\TBD@f }%
}% end of \BDfraction computation
% we also need the biased exponent in 11bit binary
%
\oodef \TBD@e {\xintDecToBin {\the\numexpr 2048+\TBD@e\relax}}%
\oodef \BDexponent {\expandafter\@gobble\TBD@e }%
\fi
\fi
\relax
}%

\def\TBD@abort #1\relax {}

% the decimal float evaluation will be made with current value of
% \xintDigits, and printed according to the optional parameter
\newcommand\PrintAsDecimalFloat [4][16]{%
\edef\TDF@sign{#2}%
\edef\TDF@exponent{#3}%
\edef\TDF@fraction{#4}%
\if1\TDF@sign-\fi
\def\TDF@temp{11111111111}%
\ifx\TDF@temp\TDF@exponent
\xintifZero {\TDF@fraction}{infty}{NaN}%
\else
\def\TDF@temp{00000000000}%
\ifx\TDF@temp\TDF@exponent
\xintFloat [#1]
{\xintthefloatexpr 2^(-1074)*\xintBinToDec\TDF@fraction\relax}%
\else
\odef\TDF@fraction {\expandafter1\TDF@fraction}%
\xintFloat [#1]
{\xintthefloatexpr
2^(\xintBinToDec\TDF@exponent-1023)*
(\xintBinToDec\TDF@fraction/2^52)\relax}%
\fi
\fi
}

\makeatother

\newcommand\PrintCurrentDouble
{\BDsign
\xintifZero{\BDexponent}{\textcolor{red}}
{\xintifEq{\BDexponent}{11111111111}{\textcolor{red}}{\textcolor{blue}}}%
{\BDexponent}%
\BDfraction
}

\newcommand\CurrentDoubleAsDecimalFloat
{{\xintDigits:=18;\PrintAsDecimalFloat\BDsign\BDexponent\BDfraction}}

\newcommand\Test [1]{\texttt{\detokenize{#1}}
(\xintFloat [16]{#1})\newline\ToDouble{#1}
\PrintCurrentDouble
${}\to{}$\CurrentDoubleAsDecimalFloat \par}

\begin{document}
First line of each paragraph shows the number as input to the conversion
routine, then within parentheses its conversion to a decimal floating
number with 16 digits of precision, then on the next line the 64bit
double representation and next the reconstructed number
as a floating decimal evaluated with 18 digits of precision and printed
with 16. Notice that \verb|\xintFloat| outputs \verb|10.000..00eN| when
the rounding went up.

\Test{3.14159}
\Test{-3.14159}
\Test{3.14159265}
\Test{3.141592653590}
\Test{3.14159265358979324}
\Test{1[-20]}
\Test{1[-200]}
\Test{1.2345678987654321e-304}
\Test{1.2345678987654321e-312}
\Test{1.2345678987654321e-320}
\Test{1[-400]}
\Test{-1[-2000]}
\Test{1[20]}
\Test{1[200]}
\Test{1[400]}
\Test{1[2000]}
\Test{\xinttheiexpr 2^50\relax}
\Test{\xinttheiexpr 2^100\relax}
\Test{\xinttheiexpr 2^150\relax}
\Test{\xinttheiexpr 2^200\relax}
\Test{1234/4567}

We also obtain, computing with 18 decimal digits and printing 17:
\xintDigits := 18;

\begin{tabular}{rl}
minimal subnormal double&
\PrintAsDecimalFloat [17]
{0}{00000000000}{0000000000000000000000000000000000000000000000000001}\\
maximal subnormal double&
\PrintAsDecimalFloat [17]
{0}{00000000000}{1111111111111111111111111111111111111111111111111111}\\
minimal normal double&
\PrintAsDecimalFloat [17]
{0}{00000000001}{0000000000000000000000000000000000000000000000000000}\\
maximal normal double&
\PrintAsDecimalFloat [17]
{0}{11111111110}{1111111111111111111111111111111111111111111111111111}\\
\end{tabular}
\end{document}


-
I am a bit perplexed by the fact that 10010010000111111010000 converted to decimal and divided by 2^22 gives 1.141590118408.., and not circa 3.14159. Is this binary sequence the correct one? –  jfbu Mar 2 at 22:36
Excellent, thanks! To answer your question, IEEE floating point normalizes the binary representation of the fraction to have a leading 1 which isn't stored, so the actual fraction is 1.10010010000111111010000. –  Merad Mar 2 at 22:45
ah! ok. Alright, if you are interested it is possible using xintbinhex to actually go from decimal to the binary float. –  jfbu Mar 2 at 22:47

In case you don't know it, bytefield package can be used to type binary values. Its main goal is drawing protocol data fields, but can be used for any kind of data field.

It just type what you want, but you can not use it to convert from binary to decimal like jbfu proposes with his great xint package.

A little example with bytefield

\documentclass{article}
\usepackage{bytefield}
\usepackage{xcolor}
\usepackage{graphicx}

\newcommand{\colorbitbox}[3]{%
\rlap{\bitbox{#2}{\color{#1}\rule{\width}{\height}}}%
\bitbox{#2}{#3}}
\definecolor{lightcyan}{rgb}{0.84,1,1}
\definecolor{lightgreen}{rgb}{0.64,1,0.71}
\definecolor{lightred}{rgb}{1,0.7,0.71}

\begin{document}

\texttt{bytefield} package helps you to draw data fields.

\begin{center}
\begin{bytefield}[bitheight=\widthof{~Sign~},
boxformatting={\centering\small}]{32}
\colorbitbox{lightcyan}{1}{\rotatebox{90}{Sign}} &
\colorbitbox{lightgreen}{8}{Exponent} &
\colorbitbox{lightred}{23}{Mantissa}
\end{bytefield}
\end{center}

You can also fill specify every bit

\begin{center}
\begin{bytefield}[bitheight=\widthof{~Sign~},
boxformatting={\centering\small}]{32}
\colorbitbox{lightcyan}{1}{0} &
\colorbitbox{lightgreen}{1}{1} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightgreen}{1}{0} &
\colorbitbox{lightred}{1}{1} &
\colorbitbox{lightred}{1}{1} &
\colorbitbox{lightred}{1}{1} &
\colorbitbox{lightred}{1}{1} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\colorbitbox{lightred}{1}{0} &
\end{bytefield}
\end{center}

or use an hexadecimal format to simplify typping

\begin{center}
\begin{bytefield}[bitheight=\widthof{~Sign~},
boxformatting={\centering\small}]{32}