36

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.

6 Answers6

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}
John Kormylo
  • 79,712
  • 3
  • 50
  • 120
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}
Manuel
  • 27,118
  • 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. –  Aug 29 '15 at 17:38
  • @jfbu You could add your answer. – Manuel Aug 29 '15 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). –  Aug 29 '15 at 20:58
28

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}
Sean Allred
  • 27,421
  • 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 05 '15 at 09: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 05 '15 at 15:24
  • @SvendTveskæg Compile with plain TeX. – Manuel Jul 06 '15 at 11:07
  • @SvendTveskæg Specifically, a TeX with e-TeX extensions (e.g. pdftex). – Sean Allred Jul 06 '15 at 11:09
  • @SvendTveskæg See edit – Sean Allred Jul 06 '15 at 11:18
  • @SeanAllred Thank you very much! (I've probably accept your answer instead.) Assume I want a \, after each three digits in order to group them. How do I do that? (I don't seem to be abel to use \num from siunitx.) – Svend Tveskæg Jul 06 '15 at 11:50
  • @SvendTveskæg See edit – Sean Allred Jul 06 '15 at 12:15
  • @SvendTveskæg The reason you couldn't use \num directly was because there was no place to put it. Either you put it in the data (around the numbers) and TeX complains that \num isn't a digit or you put \num around the entire fraction, which doesn't work for obvious reasons. Now, there's a way to insert the wrapper at the appropriate place. – Sean Allred Jul 06 '15 at 12:22
  • 2
    @SeanAllred \use:n? – Manuel Jul 06 '15 at 12:22
  • @Manuel Of course I miss the obvious :) Thanks – Sean Allred Jul 06 '15 at 12:30
  • 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. – Sean Allred Jul 06 '15 at 12:44
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

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}\]
gigiair
  • 1,812
  • 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 08 '21 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 08 '21 at 18:25