# How can I illustrate point decimal number to binary conversion

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.

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

and I want to stop it after p iterations if necessary:

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 ?

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}


Here is for binary to decimal conversion

\documentclass{article}
\usepackage{xintexpr}% we could load xintfrac only, but anyhow
\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}


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


• 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. Feb 20, 2018 at 9:41
• Excuse me, I forgot to say : "as you made ( jbfu) in your answer : tex.stackexchange.com/questions/96399/… " I'd like the same thing as base_expansion, and todecimal , but for numbers as 0.4075 or 0.4A6 for example. Feb 20, 2018 at 10:02
• 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.
– user4686
Feb 20, 2018 at 12:39
• you did already. If you insist I can communicate my PayPal® account...
– user4686
Feb 21, 2018 at 9:58
• 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).
– user4686
Feb 21, 2018 at 18:50