Creating figures to show binary values

edit (2017) of the second half of the answer: since October 2014 this part of the answer was broken due to a redefinition at xint 1.1 of \xintFloor whose original meaning as used here is now in macro named \xintiFloor. Also behaviour of \xintFloat changed a bit at xint 1.2k (2017/01/06) for the case of rounding up to a power of ten, so image of output had to be updated.

One can indeed define a command and automatize a bit.

binary bits

\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:
   % (since 1.1 we need to use \xintiFloor to get an integer,
   %  as \xintFloor adds a trailing /1[0] for better efficiency
   %  in chaining xintfrac.sty macros)
   \oodef\TBD@y {\xintiFloor {\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\TBD@f {\xintDecToBin {\xintiiAdd {4503599627370496}{\TBD@w}}}%
          \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
       % inserts a leading 1
       \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.
% This comment of original answer is false since xint 1.2k (2017/01/06):
% %%   Notice that \verb|\xintFloat| outputs \verb|10.000..00eN| when
% %%   the rounding went up.
% Policy was modified at xint 1.2k and output always has total of P digits
% with P the floating point precision: so 1.00..., not 10.00...

\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}

enter image description here


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}
\bitheader[endianness=big]{31,23,0} \\
\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}
\bitheader[endianness=big]{31,23,0} \\
\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}
\bitheader[endianness=big]{31,30,23,22,0} \\
\colorbitbox{lightcyan}{1}{0} &
\colorbitbox{lightgreen}{8}{0x80} &
\colorbitbox{lightred}{23}{0x7A0800}\\
\bitbox[]{1}{\rotatebox{90}{Sign}} & \bitbox[]{8}{Exponent} & \bitbox[]{23}{Mantissa}\\
\end{bytefield}
\end{center}
\end{document}

enter image description here