35

Consider the following code:

\documentclass{article}

\begin{document}

\noindent
Can I make \LaTeX{} reduce a fraction automatically?\\[\baselineskip]
For example, I would like the fraction
\[ \frac{278\,922}{74\,088} \]
to be reduced to
\[ \frac{6641}{1764} \]

\end{document}

output

P.S. The numerator and denominator are always both natural numbers in my case.

2

7 Answers 7

27

An expl3 implementation:

\nonstopmode \input expl3-generic \relax \ExplSyntaxOn % -*- expl3 -*-

\cs_new:Nn \svend_gcd:nn
  {
    \int_compare:nNnTF {#2} = { 0 } {#1}
      { \svend_gcd:ff {#2} { \int_mod:nn {#1} {#2} } }
  }
\cs_generate_variant:Nn \svend_gcd:nn { ff }

\int_new:N \l__svend_tmp_int
\cs_new:Nn \svend_reduced:nn
  {
    \int_set:Nn \l__svend_tmp_int { \svend_gcd:nn {#1} {#2} }
    { \int_eval:n { #1 / \l__svend_tmp_int } }
    \over
    { \int_eval:n { #2 / \l__svend_tmp_int } }
  }

$$ \svend_reduced:nn {278922} {74088} $$

\bye

LaTeX version:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% ... code code code

\msg_new:nnn { svend } { malformed-fraction }
  {
    The~input~you~have~provided~is~malformed.~
    Please~provide~input~in~the~form~of~`p/q'.
  }

\NewDocumentCommand \ReducedFraction { > { \SplitList { / } } m }
  {
    \int_compare:nTF { \tl_count:n {#1} = 2 }
      { \svend_reduced:nn #1 }
      { \msg_error:nn { svend } { malformed-fraction } }
  }

\ExplSyntaxOff

\begin{document}
\[ \ReducedFraction{278922/74088} \]
\end{document}

Edit with wrapper

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new:Nn \svend_gcd:nn
  {
    \int_compare:nNnTF {#2} = { 0 } {#1}
      { \svend_gcd:ff {#2} { \int_mod:nn {#1} {#2} } }
  }
\cs_generate_variant:Nn \svend_gcd:nn { ff }

\int_new:N \l__svend_tmp_int
\cs_new:Nn \svend_reduced:nn
  {
    \int_set:Nn \l__svend_tmp_int { \svend_gcd:nn {#1} {#2} }
    \frac { \svend_reduced_wrap:n { \int_eval:n { #1 / \l__svend_tmp_int } } }
          { \svend_reduced_wrap:n { \int_eval:n { #2 / \l__svend_tmp_int } } }
  }
\cs_new:Nn \svend_reduced_use_wrapper:N
  { \cs_set_eq:NN \svend_reduced_wrap:n #1 }
\svend_reduced_use_wrapper:N \use:n

%%% Interface

\msg_new:nnn { svend } { malformed-fraction }
  {
    The~input~you~have~provided~is~malformed.~
    Please~provide~input~in~the~form~of~`p/q'.
  }

\NewDocumentCommand \ReducedFractionWrapper { m }
  { \svend_reduced_use_wrapper:N #1 }

\NewDocumentCommand \ReducedFraction { o > { \SplitList { / } } m }
  {
    \group_begin:
    \IfValueT{#1}{\ReducedFractionWrapper{#1}}
    \int_compare:nTF { \tl_count:n {#2} = 2 }
      { \svend_reduced:nn #2 }
      { \msg_error:nn { svend } { malformed-fraction } }
    \group_end:
  }
\ExplSyntaxOff

\usepackage{siunitx}
\begin{document}
\[ \ReducedFraction[\num]{278922/74088} \]

\ReducedFractionWrapper{\num}

\[ \ReducedFraction{27892/74088} \]
\end{document}
11
  • 3
    I'd use \svend_gcd:ff in the inner calls (define a variant), or the arguments will grow up at each recursion. At one stage, the second argument to \svend_gcd:nn in your example is \int_mod:nn {\int_mod:nn {278922}{74088}}{\int_mod:nn {74088}{\int_mod:nn { 278922}{74088}}}
    – egreg
    Jul 5, 2015 at 9:24
  • The example computation requires just a few steps, but with, say, 100 of them,… It's a performance problem: with the present code you're continuously redoing computations you've already made.
    – egreg
    Jul 5, 2015 at 15:24
  • @SvendTveskæg Compile with plain TeX.
    – Manuel
    Jul 6, 2015 at 11:07
  • 2
    @SeanAllred \use:n?
    – Manuel
    Jul 6, 2015 at 12:22
  • 1
    @SvendTveskæg Yes :) I really recommend reading up on expl3, though (texdoc interface3 is also invaluable). When it comes right down to it, it's still TeX. Jul 6, 2015 at 12:44
41

Here is a flat LaTeX2e implementation.

\documentclass{article}
\usepackage{amsmath}

\newcount{\numerator}
\newcount{\denominator}
\newcount{\gcd}

% compute \gcd and returns reduced \numerator and \denominator
\newcommand{\reduce}[2]% #1=numerator, #2=denominator
{\numerator=#1\relax
 \denominator=#2\relax
 \loop
 \ifnum\numerator<\denominator
   \advance\denominator by -\numerator
   \gcd=\denominator
 \else
   \advance\numerator by -\denominator
   \gcd=\numerator% swap
 \fi
 \ifnum\gcd>1 \repeat
 \ifnum\gcd=0 \gcd=\denominator\fi
 \numerator=#1\relax
 \divide\numerator by \gcd
 \denominator=#2\relax
 \divide\denominator by \gcd
}

\begin{document}

For example, I would like the fraction
\begin{equation*}
  \frac{278922}{74088}
\end{equation*}
to be reduced to\reduce{278922}{74088}
\begin{equation*}
  \frac{\the\numerator}{\the\denominator} =
  \frac{6641}{1764}
\end{equation*}

\end{document}
0
33

If you are not bound to expl3 (in which case you “just” need to implement the algorithm):

\documentclass{scrartcl}
\usepackage{xintgcd,xintfrac}

\newcommand*\reducedfrac[2]
  {\begingroup
     \edef\gcd{\xintGCD{#1}{#2}}%
     \frac{\xintNum{\xintDiv{#1}{\gcd}}}{\xintNum{\xintDiv{#2}{\gcd}}}%
   \endgroup}

\begin{document}
\[
  \frac{278922}{74088} = \reducedfrac{278922}{74088}
\]
\end{document}
4
  • 1
  • 2
    command \xintIrr from xintfrac (no need then to load extra package xintgcd) does the job: \xintIrr{278922/74088} expands to 6641/1764. To typeset as a TeX fraction, there is typesetting macro \xintFrac (using LaTeX's \frac under the hood), thus \newcommand*\reducedfrac [2]{\xintFrac{\xintIrr{#1/#2}}} should do the job.
    – user4686
    Aug 29, 2015 at 17:38
  • @jfbu You could add your answer.
    – Manuel
    Aug 29, 2015 at 20:36
  • @Manuel I would if the question made it clear that numbers with more than ten digits (or decimal mark and decimal digits) were involved ... yours is perfectly fine and sufficient and there are already quite a few other answers. Slightly simpler: \frac{\xintNum{#1/\gcd}}{\xintNum{#2/\gcd}}, and, again assuming that #1 and #2 are guaranteed to be given as integers, \xintiiGCD has less overhead than \xintGCD (the latter accepts fractional inputs which it truncates to integers).
    – user4686
    Aug 29, 2015 at 20:58
30

An option using Lua+LaTeX.

Made small improvement. Made a Lua function to be called as a LaTeX command, with the numerator and denominator passed as arguments, instead of hardcoding the values in as before. The command is \simplify{a}{b}:

\documentclass{article}
\usepackage{luacode}
\usepackage{amsmath}    
%------------------------
\begin{luacode}
function simplify(a,b)     
  local function gcd(a,b)   
    if b ~= 0 then
        return gcd(b, a % b)
    else
        return math.abs(a)
    end
  end

  t = gcd(a, b)
  tex.print("\\frac{"..a/t.."}{"..b/t.."}")
end    
\end{luacode}
\newcommand\simplify[2]{\directlua{simplify(#1,#2) }}%
%-------------------    
\begin{document}    
\noindent Can I make \LaTeX{} reduce a fraction automatically?\\[\baselineskip]
For example, I would like the fraction
\begin{equation*}
  \frac{278\,922}{74\,088}
\end{equation*}

to be reduced to

\begin{equation*}
  \simplify{278922}{74088}
\end{equation*}    
\end{document}

Original answer

\documentclass{article}
\usepackage{luacode}
\usepackage{amsmath}

\begin{document}

\noindent Can I make \LaTeX{} reduce a fraction automatically?\\[\baselineskip]
For example, I would like the fraction
\begin{equation*}
  \frac{278\,922}{74\,088}
\end{equation*}
to be reduced to
%------------------------------------
\begin{luacode*}
function gcd(a,b)
    if b ~= 0 then
        return gcd(b, a % b)
    else
        return math.abs(a)
    end
end
u = 278922
v = 74088
t = gcd(v, u)
tex.print("\\begin{equation*}")
tex.print("  \\frac{"..u/t.."}{"..v/t.."}")
tex.print("\\end{equation*}")
\end{luacode*}
%------------------------------------

\end{document}

lualatex foo.tex gives

Mathematica graphics

references http://rosettacode.org/wiki/Greatest_common_divisor#Lua and http://www.lua.org/manual/5.3/manual.html

1
  • You should use math.floor(a / t) and math.floor(b / t).
    – projetmbc
    Mar 10, 2021 at 11:06
13

Here is a solution using R for the computations and the R-package knitr to link back to the LaTeX file.

\documentclass{article}

\begin{document}
Using R with the package 'knitr' to reduce the fraction and then get both the reduced fraction but also the components of the fraction. 

Note: This is a quick demo of linking R and LaTeX using the 'knitr' package. This has been run on Windows 8.1, with MikTeX 2.9, and TeXmaker 4.4.1 as the IDE. The following code is saved as \textbf{knit02.Rnw} (and this is case sensitive). With the package 'knitr' installed in R 3.1.3 you run the command: \emph{knit("knit02.Rnw")}. This will generate the file \textbf{knit02.tex} which you now compile with pdflatex and view as a pdf.

<<echo=FALSE>>=
library(MASS)
## This function is from http://stackoverflow.com/questions
## /14820029/getting-numerator-and-denominator-of-a-fraction-in-r
getfracs <- function(frac) {
  tmp <- strsplit(attr(frac,"fracs"), "/")[[1]]
  list(numerator=as.numeric(tmp[1]),denominator=as.numeric(tmp[2]))
}
dd<-278922
nn<-74088
x<- fractions(dd/nn)
fracs<-getfracs(x)
denom<-fracs$denominator
numer<-fracs$numerator
@
\medskip

The original fraction is $\displaystyle{\frac{\Sexpr{as.integer(dd)}}{\Sexpr{as.integer(nn)}}}$.
\medskip
The reduced fraction components are \Sexpr{fracs}.
\medskip

The reduced denominator is \Sexpr{denom}.
\medskip

The reduced numerator is \Sexpr{numer}.
\medskip

And the reduced fraction is $\displaystyle{\frac{\Sexpr{denom}}{\Sexpr{numer}}}$

\end{document}

And the output using pdflatex:

enter image description here

0
3

There's already another LuaTeX answer, but IMO it doesn't handle properly with locality and integer division. So here, and taking advantage of the fact Lua 5.3+ includes bitwise operators, a different approach using a binary GCD algorithm:

\documentclass{standalone}
%\usepackage{amsmath}
\usepackage{luacode}
\begin{luacode*}
userdata = userdata or {}

--https://xlinux.nist.gov/dads/HTML/binaryGCD.html
userdata.gcd = function (u,v)
    --To handle with negative values
    local u, v, g = math.abs(u), math.abs(v), 1
    --Nice error message
    assert(v~=0, "Denominator cannot be zero")
    while u&1==0 and v&1==0 do
        u=u>>1
        v=v>>1
        g=g<<1
    end
    while u>0 do
        if u&1==0 then 
            u=u>>1
        elseif v&1==0 then
            v=v>>1
        else 
            local t = math.abs(u-v)>>1
            if u<v then v=t else u=t end
        end
    end
    return v*g
end

userdata.simplified = function(u,v)
    local gcd = userdata.gcd(u,v)
    tex.sprint(("\\frac{%d}{%d}")
    :format(u//gcd, v//gcd))
end

\end{luacode*}
\newcommand\simplified[2]{\directlua{userdata.simplified(#1,#2)}}
\begin{document}
$\displaystyle\simplified{278922}{74088}$
\end{document}

enter image description here

The binary algorithm is slightly faster, but that's only noticeable when simplified fractions are extensively used in a document.

2

If you are an Emacs user, just call Calc embedded (C-x * e) while the point is on

\[ \frac{278922}{74088} \]

and the expression is transformed to

\[ \frac{6641}{1764} \] 

`C-x * e' a second time to come back to latex-mode.

Similarly Emacs Calc can perform reduction for rational fractions, for example

  \[\frac{x^3 - x^2 - x - 2}{2 * x^3 - x^2 - x - 3}\]

"C- * e" to enter the calc embedded mode and the command "a f" product

  \[\frac{x - 2}{2 x - 3}\]
2
  • Get an error: C-x * (Type ? for a list of Calc options) typed e. Error: calc-embedded-make-info: Symbol’s value as variable is void: the-language
    – Keks Dose
    Mar 8, 2021 at 16:39
  • @ Keks Dose: I have tested on Emacs-version 27.1 launched with emacs -q . Try M-x calc-embedded. (info "(calc) Embedded Mode")
    – gigiair
    Mar 8, 2021 at 18:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .