Я хотел бы преобразовать десятичное число с точкой в двоичное, как это сделано командой \baseexpansion
в ответе jfbu на вопрос:
Как проиллюстрировать преобразование десятичных чисел в двоичные?
Например, я хотел бы преобразовать числа типа 0.4075 в base b
или типа 0.A46C в base 10
. К сожалению, я не знаю, как это запрограммировать в LaTeX.
Кто-нибудь сделал это? Ксавье.
Для большей точности: Я хотел бы получить ментальную схему:
и я хочу остановить его после p итераций, если это необходимо:
Если у вас есть лучший алгоритм для демонстрации на LaTeX, я буду очень рад.
Спасибо! Вы проделали замечательную работу!
Наконец, могу ли я сделать то же самое для любого основания от 2 до 36, но записать результат буквами, как на рисунке ниже?
решение1
Вы не можете преобразовать десятичную систему в двоичную точно, потому что 1/5 требует бесконечно много коэффициентов. (Хотя мы можем написать код, чтобы получить периодическое расширение)
Что касается перехода от шестнадцатеричной системы счисления к десятичной, это доступно в xintexpr
.
Но поскольку результат будет использовать xintfrac
внутреннюю нотацию, я также беру \PolDecToString
макрос из polexpr 0.4
. (совсем недавний, вам может потребоваться обновить вашу установку TeX).
\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}
Вот для преобразования двоичного кода в десятичный
\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}
После добавления калькуляционных листов в OP, показ искал дизайн.
Обратите внимание, что все вычисления точны, и не может быть никаких ошибок, как это видно в расчетных таблицах OP.
Можно было бы добавить детектор периода, но память всей предыдущей дробной части должна быть сохранена (становится проблемой, если у вас есть период длиной порядка 1000000, например). Обычно период начинается сразу после десятичной точки, и мы можем определить, когда он начинается позже. Тем не менее, верно, что период может быть очень большим:
Рассмотрим пример 0.521728515624
с основанием 16
.
1000000000000=10^12
Это 16^3
раз 5^12
. Таким образом, у нас будет период, который (за исключением чудесного числового совпадения) будет начинаться с 3 цифр после десятичной точки. Длина периода (здесь числитель является простым числом 5) будет порядком 16
в мультипликативной группе Z/5^12 Z
.
phi(5^12) = 5^12 - 5^11 = 4 * 5^11 = 195312500
Затем
>>> for i in [2, 4, 5]:
... pow(16, 195312500//i, 244140625)
...
1
1
97656251
доказывает, что 16
имеет порядок 5^11 = 48828125
в этой мультипликативной группе. Следовательно, это длина периода расширения по основанию 16 0.521728515624
: периодический шаблон имеет 48828125
цифры!
В общем, мы видим, что нахождение длины периода априори очень тесно связано с факторизацией чисел. Все вычисления выше могли бы быть выполнены довольно быстро с помощью подходящей программы xintexpr, поскольку простые множители (очень) малы. Когда мы начинаем иметь простые множители с более чем 8 цифрами, это становится сложной задачей для вычислений, использующих только макрорасширение TeX!
Я не использовал табличный формат для разрешения разрыва страницы, лучше всего было бы использовать TeX, \halign
вы также можете использовать среду табуляции LaTeX (никогда не тестировалось). Или просто поля фиксированной ширины.
\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}
Последнее обновление. Изображения обновлены, чтобы соответствовать этому.
\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}