summaryrefslogtreecommitdiff
path: root/macros/generic/calcfrac/calcfrac.tex
diff options
context:
space:
mode:
Diffstat (limited to 'macros/generic/calcfrac/calcfrac.tex')
-rw-r--r--macros/generic/calcfrac/calcfrac.tex246
1 files changed, 246 insertions, 0 deletions
diff --git a/macros/generic/calcfrac/calcfrac.tex b/macros/generic/calcfrac/calcfrac.tex
new file mode 100644
index 0000000000..7d46762f95
--- /dev/null
+++ b/macros/generic/calcfrac/calcfrac.tex
@@ -0,0 +1,246 @@
+% ____________________________________
+
+% calcfrac
+% v0.1
+% 26/10/2023
+
+% TeX & LaTeX package
+% ____________________________________
+
+% Author : TeXpérimental
+% Email : texperimental@mailo.fr
+% Licence : Released under the LaTeX Project Public License v1.3c or
+% later, see http://www.latex-project.org/lppl.txt
+% Status : maintained
+
+\csname calcfraconce\endcsname
+\let\calcfraconce\endinput
+\def\calcfracname{calcfrac}
+\def\calcfracver{0.1}
+\def\calcfracdate{2023/10/26}
+
+\catcode`\@11
+\def\cf@test@ifx#1{%
+ \ifx#1\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+}
+\def\cf@test@ifnum#1{%
+ \ifnum#1\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+}
+\def\cf@execfirst#1#2{#1}
+\def\cf@execsecond#1#2{#2}
+\def\cf@execarg#1{#1}
+\def\cf@matharg#1{$#1$}
+%###########################################
+%############# boucle \cf@for ##############
+%###########################################
+\def\cf@for#1=#2to#3#{%
+ \cf@for@a{#1}{#2}{#3}%
+}
+\def\cf@for@a#1#2#3#4{%
+ \edef#1{\number\numexpr#2}%
+ \edef\cf@maxint{\number\numexpr#3}%
+ \def\cf@for@b{%
+ \unless\ifnum#1>\cf@maxint\relax
+ #4%
+ \edef#1{\number\numexpr#1+1}%
+ \expandafter\cf@for@b
+ \fi
+ }%
+ \cf@for@b
+}
+%###########################################
+%###########################################
+%###########################################
+\newcount\cf@tmp@count
+\newcount\cf@frac@cnt
+\newif\if@inparen
+\def\calcfrac@err#1#2\relax{%
+ \errmessage{Illegal char "#1", "#2" ignored}%
+}
+\def\calcfrac{%
+ \begingroup
+ \catcode32=9 % espaces ignorés
+ \calcfrac@a
+}
+\def\calcfrac@a#1{%
+ \endgroup
+ \ifcat\relax\detokenize{#1}\relax
+ \else
+ \cf@frac@cnt=0
+ \@inparenfalse
+ \expandafter\cf@read@frac\detokenize{#1}\relax
+ \fi
+}
+\def\cf@read@frac{% [1 signe optionnel + ou-]<entier non signé>[1 signe / ou * suivi d'un entier non signé]*n
+ \advance\cf@frac@cnt1
+ \let\cf@current@sign\empty
+ \def\cf@current@numer{1}%
+ \def\cf@current@denom{1}%
+ \def\cf@current@op{*}%
+ \cf@read@sign
+}
+\def\cf@read@sign#1{%
+ \cf@test@ifnum{0\ifx+#11\fi\ifx-#11\fi=1 }
+ {%
+ \def\cf@current@sign{#1}%
+ \cf@read@int
+ }
+ {%
+ \cf@read@int#1%
+ }%
+}
+\def\cf@read@int#1{%
+ \cf@test@ifnum{0\ifnum`#1<`0 1\fi\ifnum`#1>`9 1\fi=0 }
+ {%
+ \afterassignment\cf@update@afterint
+ \cf@tmp@count#1%
+ }
+ {% TODO : si #1=parenthèse
+ \if(#1\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+ {%
+ \begingroup
+ \@inparentrue
+ \cf@frac@cnt=0
+ \cf@read@frac
+ }
+ {%
+ \calcfrac@err#1%
+ }%
+ }%
+}
+\def\cf@update@afterint{%
+ \if*\cf@current@op\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+ {%
+ \edef\cf@current@numer{\cf@current@numer*\the\cf@tmp@count}%
+ \cf@read@op
+ }
+ {%
+ \if/\cf@current@op\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+ {%
+ \edef\cf@current@denom{\cf@current@denom*\the\cf@tmp@count}%
+ \cf@read@op
+ }
+ {%
+ \errmessage{This error should not occur, \string\cf@current@op=\cf@current@op}%
+ }%
+ }%
+}
+\def\cf@read@op#1{%
+ \cf@test@ifnum{0\ifx*#11\fi\ifx/#11\fi=1 }
+ {%
+ \def\cf@current@op{#1}%
+ \cf@read@int
+ }
+ {%
+ \cf@compute@frac#1%
+ }%
+}
+\def\cf@compute@frac#1{%
+ \edef\cf@current@numer{\the\numexpr\cf@current@numer}%
+ \edef\cf@current@denom{\the\numexpr\cf@current@denom}%
+ \expandafter\cf@calc@gcd\expanded{{\cf@current@numer}{\cf@current@denom}}\cf@tem@gcd
+ \expandafter\edef\csname sign@\the\cf@frac@cnt\endcsname{\ifnum\cf@current@sign1=1+\else-\fi}%
+ \expandafter\edef\csname numer@\the\cf@frac@cnt\endcsname{\the\numexpr\cf@current@numer/\cf@tem@gcd}%
+ \expandafter\edef\csname denom@\the\cf@frac@cnt\endcsname{\the\numexpr\cf@current@denom/\cf@tem@gcd}%
+ \cf@test@ifnum{0\ifx\relax#111\fi\if@inparen1\fi\if)#11\fi=11 }% si <#1=\relax> OU <inparen=vrai ET #1=")">
+ {%
+ \cf@add@allfrac
+ }
+ {%
+ \cf@read@frac#1%
+ }%
+}
+\def\cf@calc@gcd#1#2{% #1, #2=entiers
+ \cf@test@ifnum{#1>#2\relax}
+ {%
+ \cf@calc@gcd@a{#2}{#1}%
+ }
+ {%
+ \cf@calc@gcd@a{#1}{#2}%
+ }%
+}
+\def\cf@calc@gcd@a#1#2{% #1=diviseur #2=dividende
+ \cf@test@ifnum{#1>0 }
+ {%
+ \cf@tmp@count=#2\relax
+ \divide\cf@tmp@count#1\relax
+ \expandafter\cf@calc@gcd@a\expandafter{\the\numexpr#2-\cf@tmp@count*#1}{#1}%
+ }
+ {%
+ \cf@calc@gcd@b{#2}%
+ }%
+}
+\def\cf@calc@gcd@b#1#2{% #1=PGCD #2=macro qui stocke le PGCD
+ \def#2{#1}%
+}
+\def\calc@lcm#1#2#3{% #1, #2=entiers #3=macro recevant le PPCM
+ \cf@calc@gcd{#1}{#2}\cf@tem@gcd%
+ \edef#3{\the\numexpr#1*#2/\cf@tem@gcd}%
+}
+\def\cf@add@allfrac{%
+ \cf@test@ifnum{\cf@frac@cnt>1 }
+ {%
+ \expandafter\let\expandafter\cf@result@denom\csname denom@1\endcsname
+ \cf@for\cf@temp@index=2 to \cf@frac@cnt{%
+ \expandafter\calc@lcm\expanded{{\cf@result@denom}{\csname denom@\cf@temp@index\endcsname}}\cf@result@denom
+ }%
+ \def\cf@result@numer{0}%
+ \cf@for\cf@temp@index=1 to \cf@frac@cnt{%
+ \edef\cf@result@numer{%
+ \the\numexpr
+ \cf@result@numer
+ \csname sign@\cf@temp@index\endcsname% <- + ou -
+ \csname numer@\cf@temp@index\endcsname*\cf@result@denom/\csname denom@\cf@temp@index\endcsname
+ }%
+ }%
+ \ifnum\cf@result@numer<0
+ \edef\cf@result@numer{\the\numexpr-\cf@result@numer}%
+ \def\cf@result@sign{-}%
+ \else
+ \def\cf@result@sign{+}%
+ \fi
+ \expandafter\cf@calc@gcd\expanded{{\cf@result@numer}{\cf@result@denom}}\cf@tem@gcd
+ \ifnum\cf@tem@gcd>1
+ \edef\cf@result@numer{\the\numexpr\cf@result@numer/\cf@tem@gcd}%
+ \edef\cf@result@denom{\the\numexpr\cf@result@denom/\cf@tem@gcd}%
+ \fi
+ }
+ {%
+ \expandafter\let\expandafter\cf@result@sign\csname sign@1\endcsname
+ \expandafter\let\expandafter\cf@result@numer\csname numer@1\endcsname
+ \expandafter\let\expandafter\cf@result@denom\csname denom@1\endcsname
+ }%
+ \if@inparen\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+ {%
+ \expandafter
+ \endgroup
+ \expanded{%
+ \def\noexpand\cf@paren@sign{\cf@result@sign}%
+ \def\noexpand\cf@paren@numer{\cf@result@numer}%
+ \def\noexpand\cf@paren@denom{\cf@result@denom}%
+ }%
+ \edef\cf@current@sign{\cf@current@sign\cf@paren@sign}%
+ \expandafter\cf@read@int\expanded{\cf@paren@numer\if*\cf@current@op/\else*\fi\cf@paren@denom}%
+ }
+ {%
+ \expandafter\cfdisp\expanded{{\cf@result@sign}{\cf@result@numer}{\cf@result@denom}}%
+ }%
+}
+\def\cfdisp#1#2#3{%
+ \ifmmode\expandafter\cf@execfirst\else\expandafter\cf@execsecond\fi
+ {\cf@execarg}
+ {\cf@matharg}
+ {\ifnum#11=-1 -\fi
+ {\ifnum#3=1
+ #2%
+ \else
+ #2\over#3%
+ \fi
+ }%
+ }%
+}
+\catcode`\@12
+\endinput
+
+VERSIONS :
+v0.1 : version initiale \ No newline at end of file