8

I would like to format binary or hexadecimal numbers with a space separator at each 2 or 4 digit (or any other value like 8 digit or more).

A small picture is better than a long explanation, here is what I would like to do:

enter image description here

As you can see in this mwe, I use the fmtcount package with padzeroes:

    \documentclass{article}
    \usepackage[utf8]{inputenc}    
    \usepackage[T1]{fontenc}          
    \usepackage{fmtcount}
    \begin{document}
            Binary value : {\padzeroes[16]\binarynum{129}}$_{(2)}$ %
            should display 0000 0000 1000 0001$_{(2)}$

            Hexadecimal value: {\padzeroes[8]\Hexadecimalnum{65000}}$_{(16)}$ %
            should display  00 00 FD E8$_{(2)}$
    \end{document}

What I want to do is displaying numbers with various radix (2, 3, 7, 8, 10, 16) given a decimal number and format these numbers correctly with spaces and leading 0 (without having to perform the conversion by myself).

I already found some posts with similar questions, but none of them achieve this (they display number with thousand separators, like the numprint package, every 3 digits; or they do not make it automatic). Here are these posts :

EDIT two other linked questions:

I also prefer to use pdflatex.

1

2 Answers 2

8

A solution that optionally does conversion of the input given in decimal form; I can think to other improvements.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\printnumber}{O{}m}
 {
  \group_begin:
  \keys_set:nn { lauhub/printnumber } { #1 }
  \lauhub_print_number:n { #2 }
  \group_end:
 }

\tl_new:N \l_lauhub_number_tl
\tl_new:N \l_lauhub_output_tl
\int_new:N \l__lauhub_temp_int

\keys_define:nn { lauhub/printnumber }
 {
  padding  .int_set:N  = \l_lauhub_length_int,
  padding  .initial:n  = 0,
  radix    .int_set:N  = \l_lauhub_radix_int,
  radix    .initial:n  = 10,
  grouping .int_set:N  = \l_lauhub_grouping_int,
  grouping .initial:n  = 3,
  convert  .bool_set:N = \l_lauhub_convert_bool,
  convert  .default:n  = true,
  convert  .initial:n  = false,
 }

\cs_new_protected:Npn \lauhub_print_number:n #1
 {
  \tl_clear:N \l_lauhub_output_tl
  \bool_if:NTF \l_lauhub_convert_bool
   {
    \tl_set:Nx \l_lauhub_number_tl { \int_to_Base:nn { #1 } { \l_lauhub_radix_int } }
   }
   {
    \tl_set:Nn \l_lauhub_number_tl { #1 }
   }
  \prg_replicate:nn { \l_lauhub_length_int - \tl_count:N \l_lauhub_number_tl }
   {
    \tl_put_left:Nn \l_lauhub_number_tl { 0 }
   }
  \int_zero:N \l__lauhub_temp_int
  \tl_map_inline:Nn \l_lauhub_number_tl
   {
    \tl_put_right:Nn \l_lauhub_output_tl { ##1 }
    \int_incr:N \l__lauhub_temp_int
    \bool_if:nT
     {
      \int_compare_p:n
       {
        \int_mod:nn { \l__lauhub_temp_int } { \l_lauhub_grouping_int } == 0
       }
      &&
      \int_compare_p:n
       {
        \l__lauhub_temp_int < \l_lauhub_length_int
       }
     }
     {
      \tl_put_right:Nn \l_lauhub_output_tl { \, }
     }
   }
  \ensuremath
   {
    \mathrm{ \tl_use:N \l_lauhub_output_tl } \sb { ( \int_to_arabic:n { \l_lauhub_radix_int } ) }
   }
 }

\ExplSyntaxOff

\begin{document}

\printnumber[padding=16,grouping=4,radix=2]{10000001}

\printnumber[padding=16,grouping=4,radix=2,convert]{129}

\printnumber[padding=8,grouping=2,radix=16]{FDE8}

\printnumber[padding=8,grouping=2,radix=16,convert]{65000}

\end{document}

enter image description here

After setting the options, the input (possibly converted to the requested base) is padded to the left with zeroes. Then the token list is mapped: when the number of steps is a multiple of the value in grouping a thin space is added (except at the last step).

1
  • Wow, thanks ! It even does what I did not asked (but I needed) !
    – lauhub
    Feb 25, 2015 at 13:55
5

It requires the output to be set in a fixed-width font (which some would consider preferable). I do it by successively trimming the output of \padzeroes, using \chop{number}{string}.

\documentclass{article}
%\usepackage[utf8]{inputenc}
%\usepackage[T1]{fontenc}  
\usepackage{fmtcount}
\usepackage{trimclip,ifthen}
\newsavebox\numberbox
\newlength\boxoffset
\newcommand\chop[2]{%
  \bgroup\ttfamily%
  \setbox0=\hbox{0}%
  \savebox\numberbox{#2}%
  \boxoffset=0pt%
  \whiledo{\lengthtest{\boxoffset<\wd\numberbox}}{%
    \clipbox{\boxoffset+0pt 0pt \wd\numberbox-\boxoffset-#1\wd0 -1pt}{\usebox{\numberbox}}%
    \addtolength{\boxoffset}{#1\wd0}%
    \ifdim\boxoffset<\wd\numberbox\ \fi%
  }\unskip\egroup%
}
\begin{document}
Binary value : {\chop{4}{\padzeroes[16]\binarynum{129}}}$_{(2)}$ %

Hexadecimal value: {\chop{2}{\padzeroes[8]\Hexadecimalnum{65000}}}$_{(16)}$ %

\end{document}

enter image description here

2
  • 1
    That's a shame : your answer is great and does exactly what I asked for (I just add to replace \clipbox{\boxoffset+0pt 0pt with \clipbox{\boxoffset+0pt -1pt because of numbers bottom was cut). But @egreg answer also includes other features that I did not ask but that I needed. Thanks a lot for your work !
    – lauhub
    Feb 25, 2015 at 14:00
  • @lauhub Thanks for the kind words. egreg's answer is certainly better than this, but it was what I could contribute. Kind regards. Feb 25, 2015 at 16:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .