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.

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


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'.

  • 2
    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. – Paulo Cereda Jun 10 '11 at 15:40
  • 2
  • Oh no.. I did not see SageTeX has been used. :-( – Artificial Hairless Armpit Mar 4 at 16:55
  • 1
    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 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 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:





% 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\).


% read the solution
\input solution1


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:



\read\myread to \theequation
\read\myread to \thesolution



This is our equation:



And this is our solution:



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. ;-) – Paulo Cereda Jun 10 '11 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. – Paulo Cereda Jun 10 '11 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. =) – Paulo Cereda Jun 10 '11 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. – Paulo Cereda Jun 10 '11 at 19:57
  • @xport: hm your code works for me, using MikTeX 2.9. I'm gonna try in another machine with TeXLive. – Paulo Cereda Jun 10 '11 at 20:15

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


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

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


\sageplot{plot(poly) }


The output looks like this:

output from sagetex

  • 2
    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 '11 at 13:59

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

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





Let \(x_1\) and \(x_2\) be the roots of \( \Coefa x^2 +\Coefb x + \Coefc =0\). Find  \(x_1x_2\).


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


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). – Gonzalo Medina Jun 10 '11 at 16:39
  • Beautiful answer. – ℝaphink Jun 10 '11 at 17:32

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



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


% only to make some tests



\pgfmathsetmacro\xmin{\xmid-5} % to adjust the grid and the background


% minimum to adjust vertically but it's possible to use a better code
\ifnum\coeffa > 0 



enter image description here

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

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


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.

% 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
        \advance\@tempcntb by-\@tempcnta % remainder in \@tempcntb
            \ifnum\@tempcnta < 0 \@tempcnta=-\@tempcnta\fi
   \gcd{#1}{#2}{\@tempcnta=#1 \divide\@tempcnta by\thegcd
   \@tempcntb=#2 \divide\@tempcntb by\thegcd

  • 2
    @ 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 – Alain Matthes Jun 10 '11 at 17:38
  • @Altermundus that is great, I can now delete all these from my hardisk! – Yiannis Lazarides Jun 10 '11 at 17:41
  • @ Yiannis Yes great but I'm afraid ... I hope there are not too many errors in all the packages – Alain Matthes Jun 10 '11 at 17:55
  • @Altermundus See if you can also make use of tex.stackexchange.com/questions/12481/… – Yiannis Lazarides Jun 10 '11 at 18:03
  • @Yiannis I don't see this question. It's interesting – Alain Matthes Jun 10 '11 at 18:07

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

% Compile with lualatex.
function gcd (a,b) 
    if b == 0 then
        return a
    return gcd(b, a % b)

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
    elseif a ~= 1 then
    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
    if c ~= 0 then
        if c > 0 then tex.sprint('+') end

    -- 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
    if c < 0 then
        sign = -sign
        c    = -c

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


Let \(x_1\) and \(x_2\) be the roots of \(\makeproblem\). Find  \(x_1x_2\).



example output

  • +1 It is also good. However, it will become more complicated for creating more complicated math problems. – xport Jun 11 '11 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 at 21:00

MATLAB version, possibly adaptable to Octave:

First, download my parsetex.m function to somewhere in your search path. Next, make a template .tex file named foo-gradingkey.tex, with contents like


Hello, **studentName**.

% ^^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\). 

\[ x_1x_2=\frac{**c**}{**a**}= **c/a** \] 

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


Hello, Mike Renfro.

% ^^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\). 

\[ x_1x_2=\frac{10}{10}= 1 \] 

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. – xport Jun 11 '11 at 5:21
  • This approach is very fluid coding workflow. – xport Jun 11 '11 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. – Mike Renfro Jun 11 '11 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. – JohnReed Aug 5 '12 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).



  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")}

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

a1 <- a
c1 <- c

getfracs <- function(frac) {
  tmp <- strsplit(attr(frac,"fracs"), "/")[[1]]

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

num <- fracs$numerator
den <- fracs$denominator


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 b`x +`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") 


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.