[Lualatex] Division décimale posée et "périodique"

Tout ce qui concerne le langage TeX/LaTeX et ses variantes. Ce langage est utilisable sur le forum via les balises tex.
[participation réservée aux membres inscrits]
Règles du forum
Merci de soigner la rédaction de vos messages et de consulter ce sujet avant de poster. Pensez également à utiliser la fonction recherche du forum.
projetmbc
Utilisateur chevronné
Utilisateur chevronné
Messages : 2150
Inscription : samedi 29 décembre 2007, 00:58

[Lualatex] Division décimale posée et "périodique"

Message non lu par projetmbc »

Ma première contribution, même si j'estime que mon code reste un prototype de type "PdC" (Preuve du Concept). C'est une amélioration de cette proposition. Il devrait rester des bugs ... Ou pas. :mrgreen:

C'est sous licence GPL... Et plus tard sur github quand j'aurais le temps.
Code de decimaldev.lua

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
Doc. TeX de test

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}
Rendu obtenu
test.pdf
(32.53 Kio) Téléchargé 59 fois
Dernière modification par projetmbc le lundi 28 novembre 2022, 08:45, modifié 1 fois.
MB
Administrateur
Administrateur
Messages : 7898
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Re: [lualatex] Exemples d'utilisation

Message non lu par MB »

Merci pour cette contribution ! On se dirige vers un paquet de type xlop sauce luatex ?
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
projetmbc
Utilisateur chevronné
Utilisateur chevronné
Messages : 2150
Inscription : samedi 29 décembre 2007, 00:58

Re: [lualatex] Exemples d'utilisation

Message non lu par projetmbc »

Je vais faire des outils de représentations de calculs "élémentaires" dans Z , puis plus tard dans Q. Par exemple, il y aura différentes méthodes de calcul d'une multiplication : des généralistes, et d'autres astucieuses, mais juste pour certains cas particuliers.

Quant à voir si cela sera similaire à xlop, on verra, car je suis du genre YAGNI (You Ain't Gonna Need It). Le principal défaut de xlop, c'est l'impossibilité de décorer à la main les diagrammes proposés en utilisant des commandes TikZ, sauf erreur de ma part.
MB
Administrateur
Administrateur
Messages : 7898
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Re: [lualatex] Exemples d'utilisation

Message non lu par MB »

projetmbc a écrit : jeudi 10 novembre 2022, 08:44 Le principal défaut de xlop, c'est l'impossibilité de décorer à la main les diagrammes proposés en utilisant des commandes TikZ, sauf erreur de ma part.
Je n'ai personnellement jamais eu ce besoin, mais par contre j'aurais apprécié qu'il puisse gérer des bases de numération autre que la base 10. D'ailleurs, ça semble prévu pour la future version 0.3 du paquet, comme indiqué dans l'annexe C de la documentation.
- opérations en base 2 à 36 ;
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
projetmbc
Utilisateur chevronné
Utilisateur chevronné
Messages : 2150
Inscription : samedi 29 décembre 2007, 00:58

Re: [Lualatex] Division décimale posée

Message non lu par projetmbc »

Je prends note.

Pour TikZ, je m'en sers pour obtenir ce qui suit (je le mettrais dans mon package).
Capture d’écran 2022-11-28 à 08.43.18.png
MB
Administrateur
Administrateur
Messages : 7898
Inscription : samedi 28 mai 2005, 14:23
Statut actuel : Enseignant

Re: [Lualatex] Division décimale posée et "périodique"

Message non lu par MB »

Oui, ça peut effectivement être utile et c'est assez esthétique. :thumbup:
MB. (rejoignez pCloud et bénéficiez de 10Go de stockage en ligne gratuits)
Pas d'aide en message privé. Merci de consulter ce sujet avant de poster votre premier message.
conan
Utilisateur confirmé
Utilisateur confirmé
Messages : 70
Inscription : mardi 21 mars 2006, 10:10

Re: [Lualatex] Division décimale posée et "périodique"

Message non lu par conan »

On peut utiliser pstricks pour "décorer" les opérations proposées par xlop (voir doc).
On peut utiliser tikz pour "décorer" les opérations proposées par xlop (voir package ProfCollege).
projetmbc
Utilisateur chevronné
Utilisateur chevronné
Messages : 2150
Inscription : samedi 29 décembre 2007, 00:58

Re: [Lualatex] Division décimale posée et "périodique"

Message non lu par projetmbc »

Par contre, je n'ai vu nulle part la façon de poser la division que j'ai proposée.