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.

6

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).

  • Wow, thanks ! It even does what I did not asked (but I needed) ! – lauhub Feb 25 '15 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

  • 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 '15 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. – Steven B. Segletes Feb 25 '15 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.