1

I'd like to convert point decimal number to binary as made by the command \baseexpansion in the jfbu's answer to the question:

How can I illustrate decimal to binary conversion?

For example, I'd like to convert numbers like 0.4075 in base b or like 0.A46C in base 10. Unfortunaly, I don't know how to programm it in LaTeX.

Has anyone made it? Xavier.

For more precision : I'd like the mental scheme :image tableur

and I want to stop it after p iterations if necessary: enter image description here

If you have a better algorithm to be shown on LaTeX, I'll be very happy.

Thank's! You made a great work!

Finally, can I have the same thing for any base from 2 to 36 , et the result written with letters as the picture below ? finale

Xavier ANSIAUX
  • 107
  • 1
  • 8

1 Answers1

6

You can not convert from decimal to binary exactly because 1/5 needs infinitely many coefficients. (we can write code to get the periodic expansion, though)

As per going from hexadecimal to decimal, this is available in xintexpr.

But as the result will use xintfrac internal notation, I also pick up a \PolDecToString macro from polexpr 0.4. (very recent you might need to update your TeX installation).

\documentclass{article}
\usepackage{xintexpr}
\usepackage{xintbinhex}

\usepackage{polexpr}[2018/02/16]% Only for its \PolDecToString commodity!
\begin{document}
\PolDecToString{\xintREZ{\xinttheexpr "0.A46C\relax}}
\end{document}

enter image description here


Here is for binary to decimal conversion

\documentclass{article}
\usepackage{xintexpr}% we could load xintfrac only, but anyhow
% polexpr loads xintexpr
\usepackage{xintbinhex}

\usepackage{polexpr}[2018/02/16]% Only for its \PolDecToString commodity!

\makeatletter
\newcommand\FracBinToDecimal[1]{\romannumeral-`0%
  % to be used on input expanding to
  % <binary digits>[.<binary digits>]
  \expandafter\FracBin@ToDecimal\romannumeral0\xintraw{#1}%
  % the above handles this abusively as if was a decimal number with
  % only 1's and 0's
}%
\def\FracBin@ToDecimal #1/#2[#3]{% something got wrong if #2 is not 1 !
  \ifnum#3<\z@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\PolDecToString
     {\xintREZ{\xintiiMul{\xintBinToDec{#1}}{\xintiiPow{5}{-#3}}[#3]}}%
  }%
  {\xintiiMul{\xintBinToDec{#1}}{\xintiiPow{2}{#3}}}%
}%
\makeatother

\newcommand\test[1]{\[#1_b = \FracBinToDecimal{#1}_{10}\]}

\begin{document}    
\test{11001}

\test{11001.11001}

\test{0.0001}

\test{-1111.1111}
\end{document}

enter image description here


After addition of calcsheets to OP, showing looked for design.

Notice that all computations being exact there can be no errors as are apparent in OP's calcsheets.

It could be possible to add a period detector, but memory of all previous fractional part must be kept (becomes an issue if you have a period with length of the order 1000000 for example). Generically the period starts immediately after decimal mark and we can detect when it starts later. Nevertheless it is true the period can be hugely big:

Consider the 0.521728515624 to base 16 example. 1000000000000=10^12 is 16^3 times 5^12. So we will have a period which (except miraculous numerical coincidence) will start 3 digits after decimal mark. The length of the period (the numerator here is prime to 5) will be the order of 16 in the multiplicative group of Z/5^12 Z.

phi(5^12) = 5^12 - 5^11 = 4 * 5^11 = 195312500

Then

>>> for i in [2, 4, 5]:
...     pow(16, 195312500//i, 244140625)
... 
1
1
97656251

proves that 16 is exactly of order 5^11 = 48828125 in this multiplicative group. Hence this is the length of the period of the base-16 expansion of 0.521728515624: the periodic pattern has 48828125 digits!

In general, we see that finding period length a priori is very much related to factorizing numbers. All computations above could have been done rather fast by suitable xintexpr program, because the prime factors are (very) small. When we start having prime factors with more than 8 digits, this is hard challenge for computations using only TeX macro expansion!

I have not used tabular to allow page break, best would be to use some TeX \halign you can also use perhaps the tabbing environment of LaTeX (never tested). Or simply boxes of fixed widths.

\documentclass[french]{article}
\usepackage{xintfrac, xinttools}
\usepackage{polexpr}[2018/02/16]% Pour \PolDecToString
\usepackage{babel}
\usepackage[autolanguage,np]{numprint}
\usepackage{amsmath}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\newcommand\ConvertitEnHexa[2][25]{% #1 MUST BE OF THE 0.<decimal digits> type
  % (we can not use 1/5 because numprint's \np macro does not like the /)
  % the dot will be converted into a comma by \np macro
  % computes 25 digits by default. Abort earlier if all become zeros.
  \noindent Nombre à convertir en base 16: \np{#2}.\par
  \edef\ConvertitNombre{\xintRaw{#2}}%
  \xintiloop[1+1]
  \edef\ConvertitSeizeFoisNombre{\xintMul{16}{\ConvertitNombre}}%
  \edef\ConvertitSeizeFoisNombrePartieInt
      {\xintTTrunc{\ConvertitSeizeFoisNombre}}%
  \edef\ConvertitSeizeFoisNombrePartieFrac
      {\xintTFrac{\ConvertitSeizeFoisNombre}}%
  $16\times\np{\PolDecToString{\ConvertitNombre}}
             = \boxed{\ConvertitSeizeFoisNombrePartieInt} +
               \np{\PolDecToString{\ConvertitSeizeFoisNombrePartieFrac}}$\par
  \let\ConvertitNombre\ConvertitSeizeFoisNombrePartieFrac
  \xintifZero{\ConvertitNombre}{\xintbreakiloop}{}%
  \ifnum#1>\xintiloopindex\space
  \repeat
}
\newcommand\ConvertitFracEnHexa[2][25]{%
  % #1 MUST BE OR EXPAND TO A/B WITH 0 < A < B
  % computes 25 digits by default. Abort earlier if all become zeros.
  \edef\ConvertitNombre{\xintIrr{#2}}%
  \noindent Nombre à convertir en base 16: \ConvertitNombre.\par
  \xintiloop[1+1]
  \edef\ConvertitSeizeFoisNombre{\xintMul{16}{\ConvertitNombre}}%
  \edef\ConvertitSeizeFoisNombrePartieInt
      {\xintTTrunc{\ConvertitSeizeFoisNombre}}%
  \edef\ConvertitSeizeFoisNombrePartieFrac
      {\xintTFrac{\ConvertitSeizeFoisNombre}}%
  $16\times\xintFrac{\xintRawWithZeros\ConvertitNombre}
             = \boxed{\ConvertitSeizeFoisNombrePartieInt} +
               \xintFrac{\xintRawWithZeros\ConvertitSeizeFoisNombrePartieFrac}$\par
  \let\ConvertitNombre\ConvertitSeizeFoisNombrePartieFrac
  \xintifZero{\ConvertitNombre}{\xintbreakiloop}{}%
  \ifnum#1>\xintiloopindex\space
  \repeat
}

\begin{document}
\ConvertitEnHexa{0.99609375}

\bigskip

\ConvertitEnHexa{0.521728515625}
\bigskip

\ConvertitEnHexa{0.521728515624}
et ça peut continuer longtemps avant que l'on voie la période\dots\bigskip

\clearpage
\ConvertitEnHexa[12]{0.4075}
etc\dots

\bigskip

\ConvertitFracEnHexa[12]{4095/4096}

\bigskip

\ConvertitFracEnHexa[7]{1/5}
etc\dots

\bigskip

\ConvertitFracEnHexa[7]{3/7}
etc\dots

\bigskip

\clearpage

\ConvertitFracEnHexa[7]{9/11}
etc\dots

\end{document}

Last update. Images updated to correspond to this.

\documentclass[french]{article}
\usepackage{xintfrac, xinttools}
\usepackage{polexpr}[2018/02/16]% Pour \PolDecToString
\usepackage{babel}
\usepackage[autolanguage,np]{numprint}
\usepackage{amsmath}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\newcommand\MiniConvert[1]{\ifcase #1
  0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or 8\or 9\or A\or B\or C\or D\or E\or
  F\or G\or H\or I\or J\or K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or
  U\or V\or W\or X\or Y\or Z\else\ERROR\fi}%
\newcommand\ConvertitEnBaseB[3][25]{% #1 MUST BE OF THE 0.<decimal digits> type
  % (we can not use 1/5 because numprint's \np macro does not like the /)
  % the dot will be converted into a comma by \np macro
  % computes 25 digits by default. Abort earlier if all become zeros.
  % #3 = base < 36
     \def\ConvertiDots{\dots}%
  \noindent Nombre à convertir en base #3: \np{#2}.\par
  \def\Converti{0,}%<<<< LOCALIZE TO YOUR LANGUAGE
  \edef\ConvertitNombre{\xintRaw{#2}}%
  \xintiloop[1+1]
  \edef\ConvertitBFoisNombre{\xintMul{#3}{\ConvertitNombre}}%
  \edef\ConvertitBFoisNombrePartieInt
      {\xintTTrunc{\ConvertitBFoisNombre}}%
  \edef\ConvertitBFoisNombrePartieFrac
      {\xintTFrac{\ConvertitBFoisNombre}}%
  $#3\times\np{\PolDecToString{\ConvertitNombre}}
             = \boxed{\ConvertitBFoisNombrePartieInt} +
               \np{\PolDecToString{\ConvertitBFoisNombrePartieFrac}}$
  \hfill
  \llap{${}\longrightarrow{}$\MiniConvert\ConvertitBFoisNombrePartieInt}\par
  \edef\Converti{\Converti\MiniConvert{\ConvertitBFoisNombrePartieInt}}%
  \let\ConvertitNombre\ConvertitBFoisNombrePartieFrac
  \xintifZero{\ConvertitNombre}
    {\xintbreakiloopanddo\let\ConvertiDots\empty.}%
    {}%
  \ifnum#1>\xintiloopindex\space
  \repeat
  \noindent\mbox{}\hfill$\np{#2}=[$\Converti\ConvertiDots$]_{#3}$\par
}
\newcommand\ConvertitFracEnBaseB[3][25]{%
  % #1 MUST BE OR EXPAND TO A/B WITH 0 < A < B
  % computes 25 digits by default. Abort earlier if all become zeros.
     \def\ConvertiDots{\dots}%
  \edef\ConvertitNombre{\xintIrr{#2}}%
  \def\Converti{0,}%<<<< LOCALIZE TO YOUR LANGUAGE
  \noindent Nombre à convertir en base #3: \ConvertitNombre.\par
  \xintiloop[1+1]
  \edef\ConvertitBFoisNombre{\xintMul{#3}{\ConvertitNombre}}%
  \edef\ConvertitBFoisNombrePartieInt
      {\xintTTrunc{\ConvertitBFoisNombre}}%
  \edef\ConvertitBFoisNombrePartieFrac
      {\xintTFrac{\ConvertitBFoisNombre}}% does \xintREZ, not good for us
  $#3\times\xintFrac{\xintRawWithZeros\ConvertitNombre}
             = \boxed{\ConvertitBFoisNombrePartieInt} +
               \xintFrac{\xintRawWithZeros\ConvertitBFoisNombrePartieFrac}$\par
  \hfill
  \llap{${}\longrightarrow{}$\MiniConvert\ConvertitBFoisNombrePartieInt}\par
  \edef\Converti{\Converti\MiniConvert{\ConvertitBFoisNombrePartieInt}}%
  \let\ConvertitNombre\ConvertitBFoisNombrePartieFrac
  \xintifZero{\ConvertitNombre}
    {\xintbreakiloopanddo\let\ConvertiDots\empty.}%
    {}%
  \ifnum#1>\xintiloopindex\space
  \repeat
  \noindent\mbox{}\hfill$\xintFrac{#2}=[$\Converti\ConvertiDots$]_{#3}$\par}%


\begin{document}
\ConvertitEnBaseB{0.99609375}{16}

\bigskip

\ConvertitEnBaseB{0.521728515625}{16}
\bigskip

\ConvertitEnBaseB{0.521728515624}{16}
et ça peut continuer longtemps avant que l'on voie la période\dots\bigskip

\ConvertitEnBaseB[12]{0.4075}{16}
etc\dots

\bigskip

\ConvertitFracEnBaseB[12]{4095/4096}{16}

\bigskip

\ConvertitFracEnBaseB[7]{1/5}{16}
etc\dots

\bigskip

\ConvertitFracEnBaseB[7]{3/7}{16}
etc\dots

\bigskip

\ConvertitFracEnBaseB[10]{9/11}{16}
etc\dots

\bigskip

\ConvertitFracEnBaseB[10]{9/11}{15}
etc\dots

\bigskip

\ConvertitFracEnBaseB[10]{9/11}{14}
etc\dots

\bigskip

\ConvertitFracEnBaseB[15]{9/11}{13}
etc\dots

\bigskip

\ConvertitFracEnBaseB[10]{9/11}{36}
etc\dots

\bigskip

\ConvertitFracEnBaseB[15]{9/11}{2}
etc\dots
\end{document}

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

  • Hello ! Thank's you a lot! You wrote "You can not convert from decimal to binary exactly because 1/5 needs infinitely many coefficients. (we can write code to get the periodic expansion, though)"That's exactly what I 'd like to do. ( choose how many coefficients i need, then write them). More, I'd like to show to my students the algorithm who make it. – Xavier ANSIAUX Feb 20 '18 at 09:41
  • Excuse me, I forgot to say : "as you made ( jbfu) in your answer : https://tex.stackexchange.com/questions/96399/how-can-i-illustrate-decimal-to-binary-conversion " I'd like the same thing as base_expansion, and todecimal , but for numbers as 0.4075 or 0.4A6 for example. – Xavier ANSIAUX Feb 20 '18 at 10:02
  • it is not very clear to me exactly which bases you want to handle and in which direction. To you want to express say a decimal number such as 0.2 in binary notation? or do you want to express an hexadecimal fractional number 0.4A6 in decimal? (as in my answer). For the decimal to (infinite) binary there can not be one answer to "how we make it", various approaches are possible. Or you want how to express a binary fraction 101110/11100111 as an infinite expansion ? It is not clear to me what you want exactly. –  Feb 20 '18 at 12:35
  • (cont.) The latter case can be handled as long division in base 2. But we can also try to find exactly the period. For 1/a, this basically means to find the order of 2 in the mutliplicative group of Z/aZ. Depending on level of your students this requires very distinct pedagogical presentations. –  Feb 20 '18 at 12:37
  • 1
    ah I see only now update to your original question, I will look at it (I am short on time these days). OK I see your method. Yes one can do that easily with xintexpr and a loop. –  Feb 20 '18 at 12:39
  • Fantastic!! Thanks very much! I updated my question; Excuse me because I did many updates: I should have explained my needs in a better way!! – Xavier ANSIAUX Feb 20 '18 at 16:46
  • You fired faster than your shadow!! I surrender! Great thanks! – Xavier ANSIAUX Feb 20 '18 at 19:46
  • 1
    you did already. If you insist I can communicate my PayPal® account... –  Feb 21 '18 at 09:58
  • I have added some math explanations related to \ConvertitEnBaseB{0.521728515624}{16} –  Feb 21 '18 at 10:27
  • I meant : is there a button to push , to improve your reputation ... There's also a way to thank you . – Xavier ANSIAUX Feb 21 '18 at 13:09
  • With a math'course, it's perfect! – Xavier ANSIAUX Feb 21 '18 at 13:09
  • I posted two others questions (macros for presenting calculations) : – Xavier ANSIAUX Feb 21 '18 at 14:21
  • 1
    The following holds: let 0.abcd...z be an arbitrary decimal number. Then its hexadecimal writing has a period which is a power of 5. That is, it is either 1, 5, 25, 125 ... (this includes the case when the expansion is finite which we considered as ending in infinitely many repeated zeros). –  Feb 21 '18 at 18:50
  • I uninstalled and then installed Miktex on my PC. Since that, your command didn't work. I obtained this: ! Undefined control sequence. \PolDecToString
    {\ConvertitNombre }
    – Xavier ANSIAUX Mar 26 '18 at 06:48
  • I guess this is a matter of package versions. Perhaps in the log you find a message that version of polexpr is too old, or polexpr not installed at all? anyway, since xint package (1.3a 2018-03-07) it has \xintDecToString which is the same as \PolDecToString. –  Mar 26 '18 at 06:57
  • I obtain too the warning : (C:\Users\Xavier\AppData\Roaming\MiKTeX\2.9\tex\generic\xint\xintexpr.sty)

    LaTeX Warning: You have requested, on input line 5, version 2018/03/01' of package xintexpr, but only version2018/02/06 1.2q Expandable expression parser (JFB)' is available.

    )

    – Xavier ANSIAUX Mar 26 '18 at 15:21
  • On another Miktex installation ( not the lastest) , it works fine. – Xavier ANSIAUX Mar 26 '18 at 15:22
  • That's O.K. now . I uninstalled Miktex and all directories wich contained Miktex. Then I installed Miktex again. There was old files from Miktex wich involved problems .Thank's a lot! – Xavier ANSIAUX Mar 26 '18 at 16:08