创建图形来显示二进制值

创建图形来显示二进制值

我正在写一篇大量涉及浮点值的论文,我需要制作一些数字来表示 32 位二进制值。下面的代码是我编写的,从视觉上看,它基本上就是我想要的。但是,我至少想把它包装在一个函数中,因为它需要经常使用,但我无法做到这一点。我尝试将图片部分放入函数中,但一直收到有关 \begin{figure} 被 \end{document} 终止的错误。此外,如果放大该图,您会发现方框并不总是正确对齐,我不太清楚如何修复它。

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

答案1

编辑 (2017) 答案的后半部分:自 2014 年 10 月以来,答案的这一部分因重新定义而被破坏,xint 1.1\xintFloor原始含义在此处使用时现在在名为 的宏中\xintiFloor。此外,对于四舍五入到十的幂的情况,的行为\xintFloat也发生了一些变化xint 1.2k (2017/01/06),因此必须更新输出的图像。

我们确实可以定义一个命令并实现一些自动化。

二进制位

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

此外,实际上可以从十进制开始计算二进制表示(如果有人向我解释规则,我就可以实现它)。


作为补充,这里有一些代码可以转换成双二进制(参见维基百科)。输入任何可以被宏接受的内容信特压裂,在输出位上的双二进制格式64,在三个宏中\BDsign,,,\BDexponent\BDfraction由于输入可能有数百位数字,因此首先将其转换为具有24 数字精度的十进制浮点数。然后从该起点开始转换为双二进制,使用24十进制数字和十的幂指数(请注意,xint允许一直到10^2147483647,因此代码处理NaN并且它还处理次正规数)。还有一个宏反向操作。

当然,这仅说明这里实现的转换,转换的步骤在代码注释中进行了解释。

上面的代码\bitpicture 可以针对位的情况重新编写64,只需更改几处\bitpicture\BDsign\BDexponent\BDfraction即可。但在这里我选择了一种更简单的内联表示。

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

在此处输入图片描述

答案2

如果你不知道的话,字节字段包可用于输入二进制值。其主要目标是绘制协议数据字段,但可用于任何类型的数据字段。

它只输入您想要的内容,但您不能像 jbfu 在其出色的 xint 包中所建议的那样,使用它从二进制转换为十进制。

一个小例子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}

在此处输入图片描述

相关内容