C'est sous licence GPL... Et plus tard sur github quand j'aurais le temps.
Code : Tout sélectionner
-- Source used to start this file.
--
-- + https://www.mathematex.fr/viewtopic.php?p=163384#p163384
---------------------
-- LIST-LIKE TOOLS --
---------------------
function contains(list, x)
for _ , v in pairs(list) do
if v == x then
return true
end
end
return false
end
function index(list, x)
for k, v in pairs(list) do
if v == x then
return k
end
end
return -1
end
function list2str(list, sep)
local test = ''
for _, v in pairs(list) do
v = tostring(v)
if test ~= '' then
test = test .. sep
end
test = test .. v
end
return test
end
----------------
-- MATH TOOLS --
----------------
function divmod(a, b)
local q = 0
local r = a
while r >= b do
q = q + 1
r = r - b
end
return q, r
end
COMMA = '.'
function build_decidev(a, b)
-- ``local`` can't be used for q and r!
q, r = divmod(a, b)
local qlist = {q, COMMA}
local rlist = {}
while not contains(rlist, r) do
table.insert(rlist, r)
q, r = divmod(10*r, b)
table.insert(qlist, q)
end
local i_period = index(rlist, r) + 2
return qlist, i_period
end
function digitsfromlist(nlist, nocomma, nolastzero)
local digits = {}
local i_shift = 0
for _, v in pairs(nlist) do
if v == COMMA then
if not nocomma then
table.insert(digits, v)
end
elseif v < 10 then
table.insert(digits, v)
else
while v >= 10 do
i_shift = i_shift + 1
v, r = divmod(v, 10)
table.insert(digits, 1, r)
end
table.insert(digits, 1, v)
end
end
if nolastzero and digits[#digits] == 0 then
i_shift = -1
table.remove(digits, #digits)
end
return digits, i_shift
end
function digitstonb(digits)
local nb = 0
for _, d in pairs(digits) do
nb = 10 * nb + d
end
return nb
end
-----------------------------
-- DECIMAL PERIOD - INLINE --
-----------------------------
function decimaldev(a, b)
local qlist, i_period = build_decidev(
math.abs(a),
math.abs(b)
)
return display_inline(a, b, qlist, i_period)
end
function display_inline(a, b, qlist, i_period)
local before = (a * b < 0 and '-') or ''
local period = ''
for k, v in pairs(qlist) do
v = tostring(v)
if k < i_period then
before = before .. v
else
period = period .. v
end
end
if period == '0' then
return string.format(
[[\num{%s}]],
before
)
end
return string.format(
[[\num[retain-explicit-decimal-marker]{%s}\underline{%s}]],
before,
period
)
end
-----------------------------------
-- DECIMAL PERIOD - CALCULATIONS --
-----------------------------------
NEWLINE = '\\\\'
function decimaldivi(a, b)
a = math.abs(a)
b = math.abs(b)
local qlist, i_period = build_decidev(a, b)
local qstr = display_inline(a, b, qlist, i_period)
local adigits_left, _ = digitsfromlist({a}, true, false)
local qdigits_left, _ = digitsfromlist(qlist, true, true)
local rdigits = {table.remove(adigits_left, 1)}
-- ! DEBUGGING ! --
-- return 'r > ' .. list2str(rdigits, '::')
-- .. ' AND a > ' .. list2str(adigits_left, '::')
-- .. ' AND q > ' .. list2str(qdigits_left, '::')
-- ! DEBUGGING ! --
-- Variables used to type the table.
local content = ''
local row = ''
local prefix_row = ''
local nbcols = #adigits_left + 4
-- -- 1st line with a and b.
content = rdigits[1] .. '&'
.. list2str(adigits_left, '&')
if #adigits_left == 0 then
content = content .. '&&'
else
content = content .. '&&&'
end
content = content
.. uprightval(tostring(b))
.. NEWLINE
-- 2nd line with first r and q.
row, rdigits, adigits_left, qdigits_left, prefix_row = onerow(
rdigits,
adigits_left,
b,
qdigits_left,
prefix_row
)
content = content
.. '\\cline{' .. nbcols .. '-' .. nbcols .. '}'
.. row
for _ = 1, nbcols - string.len(prefix_row) - #rdigits do
content = content .. '&'
end
content = content
.. uprightval(qstr)
.. NEWLINE
-- Other lines with only r.
while #qdigits_left ~= 0 do
row, rdigits, adigits_left, qdigits_left, prefix_row = onerow(
rdigits,
adigits_left,
b,
qdigits_left,
prefix_row
)
content = content
.. row
.. NEWLINE
end
-- Let's build our LaTeX table.
if nbcols < string.len(prefix_row) + #rdigits - 1 then
nbcols = string.len(prefix_row) + #rdigits - 1
end
local head = '\\begin{NiceTabular}'
local tail = '\\end{NiceTabular}'
-- ! DEBUGGING ! --
-- head = '\\begin{verbatim}'
-- tail = '\\end{verbatim}'
-- ! DEBUGGING ! --
local format = '*{' .. tostring(nbcols) .. '}{c}'
return head .. '{' .. format .. '}'
.. content
.. tail
end
function uprightval(x)
return '\\multicolumn{1}{|l}{\\!\\!\\rlap{' .. x .. '}}'
end
function onerow(
rdigits,
adigits_left,
b,
qdigits_left,
prefix_row
)
local qused = table.remove(qdigits_left, 1)
-- Just add one new digit.
if qused == 0 then
rdigits, adigits_left = addonedigit(
rdigits,
adigits_left
)
-- One new remainder to calculate.
else
rdigits, adigits_left, prefix_row = calcrow(
rdigits,
adigits_left,
b,
qused,
prefix_row
)
end
-- Let's build one new row.
local row = prefix_row
for i = 1, #rdigits - 1 do
if row ~= prefix_row then
row = row .. '&'
end
row = row .. rdigits[i]
end
if #qdigits_left ~= 0 then
row = row .. '& \\digitused{' .. rdigits[#rdigits] .. '}'
end
return row, rdigits, adigits_left, qdigits_left, prefix_row
end
function calcrow(
rdigits,
adigits_left,
b,
qused,
prefix_row
)
local substract = b * qused
-- We need enough digits : think about 10 / 3.
while digitstonb(rdigits) < substract do
rdigits, adigits_left = addonedigit(
rdigits,
adigits_left
)
end
-- What is the reainder in this case?
local initial_rsize = #rdigits
local rdigits = digitsfromlist(
{
digitstonb(rdigits) - substract
},
false
)
for _ = 1, initial_rsize - #rdigits do
prefix_row = prefix_row .. '&'
end
rdigits, adigits_left = addonedigit(
rdigits,
adigits_left
)
return rdigits, adigits_left, prefix_row
end
function addonedigit(
rdigits,
adigits_left
)
local newdigit
if #adigits_left == 0 then
newdigit = 0
else
newdigit = table.remove(adigits_left, 1)
end
table.insert(rdigits, #rdigits + 1, newdigit)
return rdigits, adigits_left
end
Code : Tout sélectionner
\documentclass{article}
\usepackage{nicematrix}
\usepackage[output-decimal-marker={,}]{siunitx}
\directlua{dofile('decimaldev.lua')}
\newcommand\digitused[1]{{\color{red!75!black}#1}}
\newcommand\decimaldev[2]{\directlua{tex.sprint(decimaldev(#1,#2))}}
\newcommand\decimaldivi[2]{\directlua{tex.sprint(decimaldivi(#1,#2))}}
\newcommand\test[2]{
$\frac{#1}{#2} = \decimaldev{#1}{#2}$
\decimaldivi{#1}{#2}
}
\begin{document}
\begin{itemize}
\item \test{1000}{3}
\item \test{1258}{4}
\item \test{4}{333}
\item \test{123}{14}
\item \test{139}{11}
\item \test{10003}{11}
\item \test{5}{3}
\end{itemize}
\end{document}