# How to create a random math problem in LaTeX?

I want to create a math problem-solution sheet. The coefficients a, b, c must be assigned on the fly at random so the generated pdf will show a numeric quadratic equation rather than a symbolic quadratic equation. Note a must not be zero.

\documentclass{article}
\begin{document}
\section{Problem}
Let $$x_1$$ and $$x_2$$ be the roots of $$a x^2 +bx +c=0$$. Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\frac{c}{a}$
\end{document}


Please kindly make the solution get automatically simplified. For example: \frac{c}{a}=3 when a=2 and c=6.

Actually the real case is more complex than this one. Not only the equations must be generated at random, but also the associated graphic plots that I write in PSTricks.

I chose Paulo's answer because using Maxima as the computation engine is very very great idea. Other answers are also good and creative, especially Altermundus'.

• Pretty interesting question. I remember dealing with something similar, but my approach was quite hybrid. It was something like generating random coefficients in LaTeX, call a computer algebra system to solve it for me, then redirect the output back to LaTeX. I used Maxima's function tex(solve(equation)) which gives me the result in the LaTeX math format. Jun 10, 2011 at 15:40
• Oh no.. I did not see SageTeX has been used. :-( Mar 4, 2019 at 16:55
• Yes. That post inspired me to create a lot of tests/quizzes using specific problem types where the numbers are created at random (and then create a solution sheet) using the sagetex package. It is the package to learn if you are teaching math
– DJP
Mar 4, 2019 at 17:06
• If this is still going to be open for a bounty, what sort of random problems are you looking for: arithmetic, algebra, precalculus, discrete math? Or you still want quadratic mentioned and already solved?
– DJP
Mar 4, 2019 at 17:37

This is a partial solution and probably it's not what you want. However, I'm posting it solely for record purposes, in case anyone would need it. =)

I'll use Maxima:

Maxima is a system for the manipulation of symbolic and numerical expressions, including differentiation, integration, Taylor series, Laplace transforms, ordinary differential equations, systems of linear equations, polynomials, and sets, lists, vectors, matrices, and tensors. Maxima yields high precision numeric results by using exact fractions, arbitrary precision integers, and variable precision floating point numbers. Maxima can plot functions and data in two and three dimensions.

First of all, I created a script file named solve.cmd in my working directory:

@echo off
rem If Maxima is not in your path, you need to set it.
rem Also, I'm making use of the 'head' command, you can
rem obtain the Win32 version easily with MSys.
set PATH=%PATH%;"C:\Program Files\Maxima-5.24.0\bin"
maxima --very-quiet -r %1 | head --lines=-1


I'm not in my Linux box right now, but a .sh file is similar.

Using Jake's code, I added a call to this script:

\documentclass{article}
\usepackage{pgf}

\begin{document}

\section{Problem}

\pgfmathsetseed{1}
\pgfmathtruncatemacro\coeffa{random(2,10)}
\pgfmathtruncatemacro\coeffb{random(2,10)}
\pgfmathtruncatemacro\coeffc{random(2,10)}

% call to the 'solve' script providing the coefficients.
% Maxima's 'solve' function will return x1 and x2, and the
% 'tex' function will convert the answer to TeX. The last
% line of the output will be removed (the 'head' command)
% because Maxima adds a 'false' line to the end of the file.
% Then we redirect the output to a file.
\immediate\write18{solve.cmd "tex(solve(\coeffa*x^2 + (\coeffb*x) + (\coeffc)));" > solution1.tex}

Let $$x_1$$ and $$x_2$$ be the roots of $$\coeffa x^2 +\coeffb x +\coeffc=0$$. Find  $$x_1x_2$$.

\section{Solution}

\input solution1

\end{document}


I tried to use Maxima's plot2d function together with the call, but I failed to fix a minor error with file extensions. I intended to create a png plot with gnuplot and include it. Sorry, it didn't work yet.

Don't forget to use the --shell-escape or --enable-write18 flag.

EDIT: It gave me a tremendous headache, but I guess I found a nice improvement. =)

I'm not used to Maxima, though I like to use it for simple calculations. If my code is somehow incorrect, please help me improve it. Thanks.

I edited the solve.cmd file in my working directory to look like this:

@echo off
rem If Maxima is not in your path, you need to set it.
rem Now, I don't use 'head' anymore, but 'grep'. The idea
rem behind this code is:
rem   1. generate the three coefficients,
rem   2. output both equation and solution to a file,
rem   3. get rid of the 'false' lines in the text (Maxima's fault)
rem      (we do this thanks to 'grep' using an inverse flag)
rem   4. direct output to a file 'problem.txt'.
@echo off
set PATH=%PATH%;"C:\Program Files\Maxima-5.24.0\bin"
maxima --very-quiet -r "s: make_random_state(true)$set_random_state(s)$ fullrand(low, high) := floor(random(1.0) * ( 1 + high - low)) + low$a : fullrand(-10,10)$ s: b : fullrand(-10,10)$c : fullrand(-10,10)$ tex(a*x^2 + b*x + c); tex(solve(a*x^2 + b*x + c));" | grep -v false > problem.txt


Now the tricky part, the LaTeX code:

\documentclass{article}

\immediate\write18{solve.cmd}

\begin{document}

\section{Problem}

This is our equation:

\theequation

\section{Solution}

And this is our solution:

\thesolution

\end{document}


Let's check the code: first of all, we run solve.cmd, which outputs both equation and solution to a file named problem.txt. Then we create a \newread\myread and open this file \openin\myread=problem.txt. Now we map the first line to \theequation (which is the equation which we defined in our Maxima code) and the second line to \thesolution (same logic). Then we call it when needed.

Again, probably some of my Maxima code is faulty. But I hope you get the idea behind this. In case of changing the equation or solution to a inline version, we may probably do some sed in it and replace the pattern. =)

• @xport: glad you like it. I'm trying to improve the code as you suggested, but unfortunately I'm not that used with Maxima. EDIT: I hope to come up with something. ;-) Jun 10, 2011 at 18:55
• @xport: hm did you use the --shell-escape flag? Unfortunately, a single mistake (like a missing ;) will break the call. I suffered a lot before getting it right. Jun 10, 2011 at 19:27
• @xport: hm good, at least it worked! The missing head command is part of a Win32 port of some useful Unix tools. I uploaded mine for you to use, put in your working directory. I hope it helps. PS: I'm on a fight with Maxima right now. =) Jun 10, 2011 at 19:47
• @xport: Mine came from MSys/MinGW, but I believe it's a big payload unless you want to use gcc and related tools. This project may sound more interesting. Jun 10, 2011 at 19:57
• @xport: hm your code works for me, using MikTeX 2.9. I'm gonna try in another machine with TeXLive. Jun 10, 2011 at 20:15

I know I'm late to the party here, but I would use Sage and SageTeX:

\documentclass{article}
\usepackage{sagetex}
\begin{document}
\section{Problem}

\begin{sagesilent}
a = ZZ.random_element(-10,10)
while a == 0:
a = ZZ.random_element(-10,10)
b = ZZ.random_element(-10,10)
c = ZZ.random_element(-10,10)
poly = a*x^2 + b*x + c
\end{sagesilent}

Let $$x_1$$ and $$x_2$$ be the roots of $$\sage{poly}=0$$.
Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\sage{c/a}.$

\sageplot{plot(poly) }

\end{document}


The output looks like this:

• A little late but worth the wait! Your solution inspired me to solve the problems I had earlier (with the system finding sagetex.sty) and after spending a couple of hours messing around, it seems clear to me that sagetex package is the "must have" package for those who might use a program like Sage.
– DJP
Jul 18, 2011 at 13:59
• I am using MikTeX on a PC. SageTeX is installed but the output is missing all elements that are to come from Sage. However no error message is produced, any ideas? Also, I am interested in this because I want to make cheat-proof exams! So I like the output file to be n copies of a set of questions, (n=number of students) each copy starting on a new page utilizing a new random set of numbers. Sep 20, 2019 at 18:24

The lcg package contains macros to generate (pseudo) random numbers. A little example (the plot is also generated but using TikZ):

\documentclass{article}
\usepackage[counter=coefa,first=-8, last=12]{lcg}
\usepackage{pgfplots}

\begin{document}

\rand\arabic{coefa}
\let\Coefa\thecoefa

\chgrand[counter=coefb]
\rand\arabic{coefb}
\let\Coefb\thecoefb

\chgrand[counter=coefc]
\rand\arabic{coefc}
\let\Coefc\thecoefc

\section{Problem}
Let $$x_1$$ and $$x_2$$ be the roots of $$\Coefa x^2 +\Coefb x + \Coefc =0$$. Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\frac{\Coefc}{\Coefa}$

\begin{tikzpicture}
\begin{axis}[
xlabel=$x$,
ylabel={$f(x) = \Coefa x^2 + \Coefb x + \Coefc$}
]
\addplot[color=orange,thick] {\Coefa*x^2 + \Coefb* x + \Coefc};
\end{axis}
\end{tikzpicture}

\end{document}


Of course, when compiling my example you'll get different values for the corfficients, so a different equation and plot will be obtained.

• @xport: I'll think about the simplification problem. I've updated my answer adding the plot of the quadratic function (but using TikZ). Jun 10, 2011 at 16:39
• Beautiful answer. Jun 10, 2011 at 17:32
• When I run this I get the same coefficients unless I save the file again and then run it. Then a new set of coefficients show up. I am interested in this because I want to make cheat-proof exams! So I like the output file to be n copies of a set of questions, (n=number of students) each copy starting on a new page utilizing a new random set of numbers. Sep 20, 2019 at 18:10

Funny problem and it's a possibility to test TL 2011 with my package tkz-fct. This package calls tkz-tool-arith.tex and inside this file I define gcd and \tkzReducFrac. gcd now is a part of pgf CVS with isprime isodd and iseven. I use the code of Jake for random. The study of the function is not completed, I give this solution only to see what we can make with little tools. I compile with xelatex and with -shell-escape because tkz-fct uses only gnuplot tkzReducFrac defines two macros \tkzMathFirstResultand \tkzMathSecondResult

\documentclass{article}
\usepackage{tkz-fct}
\begin{document}
\section{Problem}

\pgfmathsetseed{1}
\pgfmathtruncatemacro\coeffa{random(2,10)}
\pgfmathtruncatemacro\coeffb{random(2,10)}
\pgfmathtruncatemacro\coeffc{random(2,10)}

Let $$x_1$$ and $$x_2$$ be the roots of $$\coeffa x^2 +\coeffb x +\coeffc=0$$. Find  $$x_1x_2$$.

\tkzReducFrac{\coeffc}{\coeffa}
\section{Solution}
$x_1x_2=\frac{\tkzMathFirstResult}{\tkzMathSecondResult}$

% only to make some tests
\pgfmathsetmacro\discrimin{\coeffb*\coeffb-4*\coeffa*\coeffc}
\pgfmathparse{ifthenelse(notless(\discrimin,0)==1,">=0","<0")}

$\Delta=b^2-4ac=\discrimin\pgfmathresult$

$a=\coeffa$

\pgfmathsetmacro\xmid{-\coeffb/(2*\coeffa)}
\pgfmathsetmacro\xmin{\xmid-5} % to adjust the grid and the background
\pgfmathsetmacro\xmax{\xmid+5}

$-b/(2a)=\xmid$

% minimum to adjust vertically but it's possible to use a better code
\ifnum\coeffa > 0
\pgfmathsetmacro\ymin{-1-\discrimin/(\coeffa*\coeffa)}
\pgfmathsetmacro\ymax{\ymin+10}
\else
\pgfmathsetmacro\ymax{-1-\discrimin/(\coeffa*\coeffa)}
\pgfmathsetmacro\ymin{\ymax-10}
\fi

\begin{tikzpicture}
\tkzInit[xmin=\xmin,xmax=\xmax,ymin=\ymin,ymax=\ymax]
\tkzGrid
\tkzAxeXY
\tkzFct[blue,thick]{\coeffa*x*x+\coeffb*x+\coeffc}
\end{tikzpicture}

\end{document}


– Vivi
Jun 11, 2011 at 9:27
• @xport: this was a good answer, but your comment here and elsewhere of "+1 for answering" implies differently.
– Vivi
Jun 11, 2011 at 21:24

To simplify the fractions, you can use Euclid's Method, using the minimal below with

\reduceFrac{27}{81}
$\frac{\rfNumer}{\rfDenom}$


will give you 1/3. To simplify to a round number is more difficult, as you need to check if there is a remainder left over, so you will need a decimal to fraction conversion routine. See How to break out of a loop at the end of the code, you will find how to use the macros to convert for example 0.375 to the fractional approximation 768/2048. No guarantees for its accuracy, needs a bit of refinement.

\documentclass{article}
\begin{document}
\makeatletter
% Use Euclid's Algorithm to find the greatest
% common divisor of two integers.
\def\gcd#1#2{{% #1 = a, #2 = b
\ifnum#2=0 \edef\next{#1}\else
\@tempcnta=#1 \@tempcntb=#2 \divide\@tempcnta by\@tempcntb
\multiply\@tempcnta by\@tempcntb  % q*b
\@tempcntb=#1
\advance\@tempcntb by-\@tempcnta % remainder in \@tempcntb
\ifnum\@tempcntb=0
\@tempcnta=#2
\ifnum\@tempcnta < 0 \@tempcnta=-\@tempcnta\fi
\xdef\gcd@next{\noexpand%
\def\noexpand\thegcd{\the\@tempcnta}}%
\else
\xdef\gcd@next{\noexpand\gcd{#2}{\the\@tempcntb}}%
\fi
\fi}\gcd@next
}
\newcommand\reduceFrac[2]
{%
\gcd{#1}{#2}{\@tempcnta=#1 \divide\@tempcnta by\thegcd
\@tempcntb=#2 \divide\@tempcntb by\thegcd
\ifnum\@tempcntb<0\relax
\@tempcntb=-\@tempcntb
\@tempcnta=-\@tempcnta
\fi
\xdef\rfNumer{\the\@tempcnta}
\xdef\rfDenom{\the\@tempcntb}}%
}

\reduceFrac{27}{81}
$\frac{\rfNumer}{\rfDenom}$
\makeatother
\end{document}

• @ Yiannis gcd is now in pgf 2.1 CVS and reduceFrac is called \tkzReducFracin tkz-tools-arith.tex. Now it's a part of TL2011. gcdis also in tkz-tools-arith.tex but I made a test to use pgfmath if the version is the CVS one . See my answer Jun 10, 2011 at 17:38
• @Altermundus that is great, I can now delete all these from my hardisk! Jun 10, 2011 at 17:41
• @ Yiannis Yes great but I'm afraid ... I hope there are not too many errors in all the packages Jun 10, 2011 at 17:55
• @Altermundus See if you can also make use of tex.stackexchange.com/questions/12481/… Jun 10, 2011 at 18:03
• @Yiannis I don't see this question. It's interesting Jun 10, 2011 at 18:07

A solution with Lua that handles coefficients that are smaller than 2 correctly.

% Compile with lualatex.
\documentclass{article}
\usepackage{luacode}
\begin{luacode*}

function gcd (a,b)
if b == 0 then
return a
end
return gcd(b, a % b)
end

function makeproblem ()
local a,b,c
a = math.random (-10,10)
if a == 0 then a = 1 end
b = math.random (-10,10)
c = math.random (-10,10)

-- Pretty-print the equation.
if a == - 1 then
tex.sprint('-')
elseif a ~= 1 then
tex.sprint(a)
end
tex.sprint( 'x^2' )
if b ~= 0 then
if b > 0 then tex.sprint('+') end
if b ~= 1 and b ~= -1 then tex.sprint(b) end
if b == -1 then tex.sprint('-') end
tex.sprint('x')
end
if c ~= 0 then
if c > 0 then tex.sprint('+') end
tex.sprint(c)
end
tex.sprint('=0')

-- Simplify the solution
local d
d = gcd(a,c)
a = a/d
c = c/d

local sign = 1
if a < 0 then
sign = -1
a    = -a
end
if c < 0 then
sign = -sign
c    = -c
end

-- Store the solution in \solution.
tex.sprint('\\gdef\\solution{')
if sign < 0 then tex.sprint('-') end
if a == 1 or c == 0 then
tex.sprint(c)
else
tex.sprint('\\frac{' .. c  ..'}{'.. a ..'}')
end
tex.sprint('}')
end

\end{luacode*}
\newcommand\makeproblem{\directlua{makeproblem()}}

\begin{document}

\section{Problem}
Let $$x_1$$ and $$x_2$$ be the roots of $$\makeproblem$$. Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\solution$

\end{document}


• +1 It is also good. However, it will become more complicated for creating more complicated math problems. Jun 11, 2011 at 5:24
• I've taken the liberty of adding a bit of meta code to pretty-print the Lua code chunk. Feel free to revert.
– Mico
Mar 4, 2019 at 21:00

MATLAB version, possibly adaptable to Octave:

\documentclass{article}

\begin{document}
Hello, **studentName**.

\section{Problem}
% ^^a=round(9*rand)+1;^^
% ^^b=round(10*rand);^^
% ^^c=round(10*rand);^^
Let $$x_1$$ and $$x_2$$ be the roots of $$**a** x^2 + **b** x + **c**=0$$.
Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\frac{**c**}{**a**}= **c/a**$
\end{document}


Paired double carets and paired double asterisks indicate MATLAB code to be evaluated. Material in paired double carets will remain in the final file, while material in pared double asterisks will be replaced with the evaluated result.

Run the following command in MATLAB:

parsetex('foo-%s.tex',{'Mike Renfro'},{'renfro'});

which results in the following message on the command line:

Creating file foo-renfro.tex: done

The contents of foo-renfro.tex will be something like

\documentclass{article}

\begin{document}
Hello, Mike Renfro.

\section{Problem}
% ^^a=round(9*rand)+1;^^
% ^^b=round(10*rand);^^
% ^^c=round(10*rand);^^
Let $$x_1$$ and $$x_2$$ be the roots of $$10 x^2 + 2 x + 10=0$$.
Find  $$x_1x_2$$.

\section{Solution}
$x_1x_2=\frac{10}{10}= 1$
\end{document}


It's not perfect, since I've not yet managed to get it to reduce fractions to simplest form, i.e., 2/5 ends up being evaluated as 0.4.

• +1: it is interesting. Unfortunately, Matlab & Mathematica are very expensive softwares. Jun 11, 2011 at 5:21
• This approach is very fluid coding workflow. Jun 11, 2011 at 5:39
• @xport: it should work in GNU Octave (this page looks like they have compatible cell arrays), but I've not tried it myself. Jun 11, 2011 at 12:55
• I haven't looked through this solution thoroughly to see if this would solve your problem with expressing decimal numbers as rational fractions, but Matlab has a rat function that might help here; however, it also might make for messy fractions when the answer is better-expressed as an approximate decimal number. Aug 5, 2012 at 13:40

Even more late to the party, but I cannot left this questions without a R/knitr approach. The MWE is in Rmarkdown but it produce a true LaTeX document compiled with pdflatex (it is on-topic).

This produce random coefficients (i a reduced range), reduce a and c when needed to obtain the smallest fraction, show the solution and if the plot will produce 0, 1 or 2 roots (intercepts) and make the plot showing that.

The MWE, as is, produce a different output in each compilation. If you want to reproduce just the images posted, uncomment set.seed(12111) or set.seed(1931) or the some similar commands that produce others possible outputs).

I left as procrastination exercises if every possible combination of coefficients work well without and search the right seed number to produce only one root (obviously, without fixing manually the coefficients).

---
output:
pdf_document: default
---

## Random coefficients

{r abc, echo=F}

# Some Reproducicle random results:
# set.seed(1235)                    # 2 roots,
# set.seed(1211)                    # 2 roots, inverted U
# set.seed(931)                     # 2 root, automatically reduced coef.
# set.seed(1931)                    # No roots
# set.seed(726)                     # No roots, inverted U
# ???????                           # One root

a <- 0
b <- 0
c <- 0

while (a==0){a=sample(-10:10, 1)}
while (b==0){b=sample(-10:10, 1)}
while (c==0|c==a){c=sample(-10:10, 1)}

# paste(a,b,c)
# b^2-(4*a*c)
# if ((b^2-(4*a*c)) > 0) {cat("OK")} else {cat("chungo")}

library(MASS)
e <- c/a
f <- attr(fractions(c/a),"fracs")

a1 <- a
c1 <- c

getfracs <- function(frac) {
tmp <- strsplit(attr(frac,"fracs"), "/")[[1]]
list(numerator=as.numeric(tmp[1]),denominator=as.numeric(tmp[2]))}

fracs <- getfracs(fractions(c/a))

num <- fracs$numerator den <- fracs$denominator
if(is.na(den)){a=a1;c=c1}else{a=den;c=num}



a = r a  (r a1/r a1/a), b = r b, c = r c (r c1/r c1/c)

## Problem

Let $$x_1$$ and $$x_2$$ be the roots of $$r a x^2 +r bx +r c=0$$. Find  $$x_1x_2$$.

## Solution

$x_1x_2=\frac{r c}{r a}= r c/a$

Since  $$b^2-4ac=r b^2-(4*a*c)$$
{r, echo=T,results='asis',echo=F}

x <- (b^2)-(4 * a * c)

if (x < 0) {cat(" (<0), there are no intercept.\n")} else
{if (x == 0) {cat(", there are one intercept.\n")}
else {cat("(>0), there are two intercepts.\n")}}


 {r, echo=F }
# , dev="tikz"
x <- seq(-5,5,.1)
y  <- (a*(x^2))+ (b*x) + c
plot(y~x, type="l",lwd=2,col="blue", bty="n",ylim=c(min(y)-10,max(y))) #
abline(v=0, lty=2, col="green")
abline(h=0, lty=2, col="red")