我正在写一篇大量涉及浮点值的论文,我需要制作一些数字来表示 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}